INT-1340 Add TCP Connection Interceptor Chain
This commit is contained in:
@@ -103,6 +103,8 @@ public abstract class IpAdapterParserUtils {
|
||||
|
||||
static final String TCP_CONNECTION_FACTORY = "connection-factory";
|
||||
|
||||
public static final String INTERCEPTOR_FACTORY_CHAIN = "interceptor-factory-chain";
|
||||
|
||||
/**
|
||||
* Adds a constructor-arg to the provided bean definition builder
|
||||
* with the value of the attribute whose name is provided if that
|
||||
|
||||
@@ -92,6 +92,8 @@ public class TcpConnectionParser extends AbstractBeanDefinitionParser {
|
||||
IpAdapterParserUtils.OUTPUT_CONVERTER);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
|
||||
IpAdapterParserUtils.SINGLE_USE);
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element,
|
||||
IpAdapterParserUtils.INTERCEPTOR_FACTORY_CHAIN);
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ public class TcpSendingMessageHandler implements MessageHandler, TcpSender {
|
||||
} catch (MessageMappingException e) {
|
||||
// retry - socket may have closed
|
||||
if (e.getCause() instanceof IOException) {
|
||||
logger.debug("Fail on first write attempt", e);
|
||||
doWrite(message);
|
||||
} else {
|
||||
throw e;
|
||||
@@ -120,13 +121,20 @@ public class TcpSendingMessageHandler implements MessageHandler, TcpSender {
|
||||
if (connection == null) {
|
||||
throw new MessageMappingException(message, "Failed to create connection");
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Got Connection " + connection.getConnectionId());
|
||||
}
|
||||
connection.send(message);
|
||||
} catch (Exception e) {
|
||||
String connectionId = null;
|
||||
if (this.connection != null) {
|
||||
connectionId = this.connection.getConnectionId();
|
||||
}
|
||||
this.connection = null;
|
||||
if (e instanceof MessageMappingException) {
|
||||
throw (MessageMappingException) e;
|
||||
}
|
||||
throw new MessageMappingException(message, "Failed to map message", e);
|
||||
throw new MessageMappingException(message, "Failed to map message using " + connectionId, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class AbstractClientConnectionFactory extends AbstractConnectionFactory {
|
||||
|
||||
protected TcpConnection theConnection;
|
||||
|
||||
/**
|
||||
* Constructs a factory that will established connections to the host and port.
|
||||
* @param host The host.
|
||||
|
||||
@@ -79,6 +79,8 @@ public abstract class AbstractConnectionFactory
|
||||
|
||||
protected boolean active;
|
||||
|
||||
protected TcpConnectionInterceptorFactoryChain interceptorFactoryChain;
|
||||
|
||||
/**
|
||||
* Sets socket attributes on the socket.
|
||||
* @param socket The socket.
|
||||
@@ -270,6 +272,13 @@ public abstract class AbstractConnectionFactory
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the singleUse
|
||||
*/
|
||||
public boolean isSingleUse() {
|
||||
return singleUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, sockets created by this factory will be used once.
|
||||
* @param singleUse
|
||||
@@ -278,10 +287,15 @@ public abstract class AbstractConnectionFactory
|
||||
this.singleUse = singleUse;
|
||||
}
|
||||
|
||||
|
||||
public void setPoolSize(int poolSize) {
|
||||
this.poolSize = poolSize;
|
||||
}
|
||||
|
||||
public void setInterceptorFactoryChain(TcpConnectionInterceptorFactoryChain interceptorFactoryChain) {
|
||||
this.interceptorFactoryChain = interceptorFactoryChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the server.
|
||||
*/
|
||||
@@ -307,6 +321,23 @@ public abstract class AbstractConnectionFactory
|
||||
this.close();
|
||||
}
|
||||
|
||||
protected TcpConnection wrapConnection(TcpConnection connection) throws Exception {
|
||||
if (this.interceptorFactoryChain == null) {
|
||||
return connection;
|
||||
}
|
||||
for (TcpConnectionInterceptorFactory factory :
|
||||
this.interceptorFactoryChain.getInterceptorFactories()) {
|
||||
TcpConnectionInterceptor wrapper = factory.getInterceptor();
|
||||
wrapper.setTheConnection(connection);
|
||||
// if no ultimate listener, register each wrapper in turn
|
||||
if (this.listener == null) {
|
||||
connection.registerListener(wrapper);
|
||||
}
|
||||
connection = wrapper;
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -65,7 +65,9 @@ public abstract class AbstractServerConnectionFactory extends AbstractConnection
|
||||
* @param socket The new socket.
|
||||
*/
|
||||
protected void initializeConnection(TcpConnection connection, Socket socket) {
|
||||
connection.registerListener(this.listener);
|
||||
if (this.listener != null) {
|
||||
connection.registerListener(this.listener);
|
||||
}
|
||||
connection.registerSender(this.sender);
|
||||
connection.setMapper(this.mapper);
|
||||
connection.setInputConverter(this.inputConverter);
|
||||
|
||||
@@ -36,10 +36,10 @@ public abstract class AbstractTcpConnection implements TcpConnection {
|
||||
|
||||
protected Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected InputStreamingConverter inputConverter;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected OutputStreamingConverter outputConverter;
|
||||
|
||||
protected TcpMessageMapper mapper;
|
||||
@@ -49,7 +49,15 @@ public abstract class AbstractTcpConnection implements TcpConnection {
|
||||
protected TcpSender sender;
|
||||
|
||||
protected boolean singleUse;
|
||||
|
||||
protected final boolean server;
|
||||
|
||||
protected String connectionId;
|
||||
|
||||
public AbstractTcpConnection(boolean server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this connection.
|
||||
*/
|
||||
@@ -78,6 +86,14 @@ public abstract class AbstractTcpConnection implements TcpConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the input converter
|
||||
*/
|
||||
public InputStreamingConverter<?> getInputConverter() {
|
||||
return inputConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param inputConverter the input converter to set
|
||||
*/
|
||||
@@ -85,6 +101,14 @@ public abstract class AbstractTcpConnection implements TcpConnection {
|
||||
this.inputConverter = inputConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the output converter
|
||||
*/
|
||||
public OutputStreamingConverter<?> getOutputConverter() {
|
||||
return outputConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param outputConverter the output converter to set
|
||||
*/
|
||||
@@ -135,4 +159,8 @@ public abstract class AbstractTcpConnection implements TcpConnection {
|
||||
return this.singleUse;
|
||||
}
|
||||
|
||||
public boolean isServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.ip.tcp.connection;
|
||||
|
||||
|
||||
import org.springframework.commons.serializer.InputStreamingConverter;
|
||||
import org.springframework.commons.serializer.OutputStreamingConverter;
|
||||
import org.springframework.integration.Message;
|
||||
|
||||
/**
|
||||
* Base class for TcpConnectionIntercepters; passes all method calls through
|
||||
* to the underlying {@link TcpConnection}.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractTcpConnectionInterceptor implements TcpConnectionInterceptor {
|
||||
|
||||
private TcpConnection theConnection;
|
||||
|
||||
private TcpListener tcpListener;
|
||||
|
||||
private TcpSender tcpSender;
|
||||
|
||||
public void close() {
|
||||
this.theConnection.close();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return this.theConnection.isOpen();
|
||||
}
|
||||
|
||||
public Object getPayload() throws Exception {
|
||||
return this.theConnection.getPayload();
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return this.theConnection.getHostName();
|
||||
}
|
||||
|
||||
public String getHostAddress() {
|
||||
return this.theConnection.getHostAddress();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.theConnection.getPort();
|
||||
}
|
||||
|
||||
public void registerListener(TcpListener listener) {
|
||||
this.theConnection.registerListener(this);
|
||||
this.tcpListener = listener;
|
||||
}
|
||||
|
||||
public void registerSender(TcpSender sender) {
|
||||
this.tcpSender = sender;
|
||||
this.theConnection.registerSender(this);
|
||||
}
|
||||
|
||||
public String getConnectionId() {
|
||||
return this.theConnection.getConnectionId();
|
||||
}
|
||||
|
||||
public boolean isSingleUse() {
|
||||
return this.theConnection.isSingleUse();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
this.theConnection.run();
|
||||
}
|
||||
|
||||
public void setSingleUse(boolean singleUse) {
|
||||
this.theConnection.setSingleUse(singleUse);
|
||||
}
|
||||
|
||||
public void setMapper(TcpMessageMapper mapper) {
|
||||
this.theConnection.setMapper(mapper);
|
||||
}
|
||||
|
||||
public InputStreamingConverter<?> getInputConverter() {
|
||||
return this.theConnection.getInputConverter();
|
||||
}
|
||||
|
||||
public void setInputConverter(InputStreamingConverter<?> inputConverter) {
|
||||
this.theConnection.setInputConverter(inputConverter);
|
||||
}
|
||||
|
||||
public OutputStreamingConverter<?> getOutputConverter() {
|
||||
return this.theConnection.getOutputConverter();
|
||||
}
|
||||
|
||||
public void setOutputConverter(OutputStreamingConverter<?> outputConverter) {
|
||||
this.theConnection.setOutputConverter(outputConverter);
|
||||
}
|
||||
|
||||
public boolean isServer() {
|
||||
return this.theConnection.isServer();
|
||||
}
|
||||
|
||||
public void onMessage(Message<?> message) {
|
||||
if (this.tcpListener == null) {
|
||||
throw new NoListenerException("No listener registered for message reception");
|
||||
}
|
||||
this.tcpListener.onMessage(message);
|
||||
}
|
||||
|
||||
public void send(Message<?> message) throws Exception {
|
||||
this.theConnection.send(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying connection (or next interceptor)
|
||||
* @return the connection
|
||||
*/
|
||||
public TcpConnection getTheConnection() {
|
||||
return this.theConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying connection (or next interceptor)
|
||||
* @param theConnection the connection
|
||||
*/
|
||||
public void setTheConnection(TcpConnection theConnection) {
|
||||
this.theConnection = theConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the listener
|
||||
*/
|
||||
public TcpListener getListener() {
|
||||
return tcpListener;
|
||||
}
|
||||
|
||||
public void addNewConnection(TcpConnection connection) {
|
||||
if (this.tcpSender != null) {
|
||||
this.tcpSender.addNewConnection(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDeadConnection(TcpConnection connection) {
|
||||
if (this.tcpSender != null) {
|
||||
this.tcpSender.removeDeadConnection(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.ip.tcp.connection;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public class NoListenerException extends NestedRuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -5644042657316429223L;
|
||||
|
||||
public NoListenerException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public NoListenerException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -106,19 +106,42 @@ public interface TcpConnection extends Runnable {
|
||||
*/
|
||||
public boolean isSingleUse();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return True if connection is used once.
|
||||
*/
|
||||
public boolean isServer();
|
||||
|
||||
/**
|
||||
* @param mapper the mapper
|
||||
*/
|
||||
public void setMapper(TcpMessageMapper mapper);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the input converter
|
||||
*/
|
||||
public InputStreamingConverter<?> getInputConverter();
|
||||
|
||||
/**
|
||||
* @param inputConverter the inputConverter to set
|
||||
*/
|
||||
public void setInputConverter(InputStreamingConverter<?> inputConverter);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the output converter
|
||||
*/
|
||||
public OutputStreamingConverter<?> getOutputConverter();
|
||||
|
||||
/**
|
||||
* @param outputConverter the outputConverter to set
|
||||
*/
|
||||
public void setOutputConverter(OutputStreamingConverter<?> outputConverter);
|
||||
|
||||
/**
|
||||
* @return this connection's listener
|
||||
*/
|
||||
public TcpListener getListener();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.ip.tcp.connection;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public interface TcpConnectionInterceptor extends TcpConnection, TcpListener, TcpSender {
|
||||
|
||||
public void setTheConnection(TcpConnection connection);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.ip.tcp.connection;
|
||||
|
||||
|
||||
/**
|
||||
* Base class for TcpConnectionInterceptorFactories. Subclasses create prototype beans by
|
||||
* default.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public abstract class TcpConnectionInterceptorFactory {
|
||||
|
||||
public abstract TcpConnectionInterceptor getInterceptor();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.ip.tcp.connection;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public class TcpConnectionInterceptorFactoryChain {
|
||||
|
||||
private TcpConnectionInterceptorFactory[] interceptorFactories;
|
||||
|
||||
public TcpConnectionInterceptorFactory[] getInterceptorFactories() {
|
||||
return interceptorFactories;
|
||||
}
|
||||
|
||||
public void setInterceptors(TcpConnectionInterceptorFactory[] interceptorFactories) {
|
||||
this.interceptorFactories = interceptorFactories;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,11 +34,4 @@ public interface TcpListener {
|
||||
*/
|
||||
public abstract void onMessage(Message<?> message);
|
||||
|
||||
/**
|
||||
* Return true if the connection factory is a server
|
||||
* and it is listening.
|
||||
* @return true if listening
|
||||
*/
|
||||
public boolean isListening();
|
||||
|
||||
}
|
||||
@@ -29,8 +29,6 @@ import javax.net.SocketFactory;
|
||||
public class TcpNetClientConnectionFactory extends
|
||||
AbstractClientConnectionFactory {
|
||||
|
||||
protected TcpNetConnection theConnection;
|
||||
|
||||
/**
|
||||
* Creates a TcpNetClientConnectionFactory for connections to the host and port.
|
||||
* @param host the host
|
||||
@@ -45,14 +43,15 @@ public class TcpNetClientConnectionFactory extends
|
||||
* true, a new connection is returned; otherwise a single connection is
|
||||
* reused for all requests while the connection remains open.
|
||||
*/
|
||||
public TcpNetConnection getConnection() throws Exception {
|
||||
public TcpConnection getConnection() throws Exception {
|
||||
if (this.theConnection != null && this.theConnection.isOpen()) {
|
||||
return this.theConnection;
|
||||
}
|
||||
logger.debug("Opening new socket connection to " + this.host + ":" + this.port);
|
||||
Socket socket = SocketFactory.getDefault().createSocket(this.host, this.port);
|
||||
setSocketAttributes(socket);
|
||||
TcpNetConnection connection = new TcpNetConnection(socket, false);
|
||||
TcpConnection connection = new TcpNetConnection(socket, false);
|
||||
connection = wrapConnection(connection);
|
||||
initializeConnection(connection, socket);
|
||||
this.taskExecutor.execute(connection);
|
||||
if (!this.singleUse) {
|
||||
|
||||
@@ -35,8 +35,6 @@ public class TcpNetConnection extends AbstractTcpConnection {
|
||||
|
||||
private final Socket socket;
|
||||
|
||||
private final boolean server;
|
||||
|
||||
/**
|
||||
* Constructs a TcpNetConnection for the socket.
|
||||
* @param socket the socket
|
||||
@@ -44,8 +42,9 @@ public class TcpNetConnection extends AbstractTcpConnection {
|
||||
* a result of an incoming request.
|
||||
*/
|
||||
public TcpNetConnection(Socket socket, boolean server) {
|
||||
super(server);
|
||||
this.socket = socket;
|
||||
this.server = server;
|
||||
getConnectionId();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,15 +120,6 @@ public class TcpNetConnection extends AbstractTcpConnection {
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* For single use sockets, we close after receipt if we are on the client
|
||||
* side, or the server side has no outbound adapter registered
|
||||
*/
|
||||
if (this.singleUse && (!this.server || this.sender == null)) {
|
||||
logger.debug("Closing single use socket after inbound message");
|
||||
this.close();
|
||||
okToRun = false;
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Message received " + message);
|
||||
try {
|
||||
@@ -139,13 +129,35 @@ public class TcpNetConnection extends AbstractTcpConnection {
|
||||
}
|
||||
listener.onMessage(message);
|
||||
} catch (Exception e) {
|
||||
logger.error("Exception sending meeeage: " + message, e);
|
||||
if (e instanceof NoListenerException) {
|
||||
if (this.singleUse) {
|
||||
logger.debug("Closing single use socket after inbound message " + this.connectionId);
|
||||
this.close();
|
||||
okToRun = false;
|
||||
} else {
|
||||
logger.warn("Unexpected message - no inbound adapter registered with connection " + message);
|
||||
}
|
||||
} else {
|
||||
logger.error("Exception sending meeeage: " + message, e);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* For single use sockets, we close after receipt if we are on the client
|
||||
* side, or the server side has no outbound adapter registered
|
||||
*/
|
||||
if (this.singleUse && this.server && this.sender == null) {
|
||||
logger.debug("Closing single use socket after inbound message " + this.connectionId);
|
||||
this.close();
|
||||
okToRun = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getConnectionId() {
|
||||
return SocketIoUtils.getSocketId(this.socket);
|
||||
if (this.connectionId == null) {
|
||||
this.connectionId = SocketIoUtils.getSocketId(this.socket);
|
||||
}
|
||||
return this.connectionId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -69,11 +69,12 @@ public class TcpNetServerConnectionFactory extends AbstractServerConnectionFacto
|
||||
final Socket socket = serverSocket.accept();
|
||||
logger.debug("Accepted connection from " + socket.getInetAddress().getHostAddress());
|
||||
setSocketAttributes(socket);
|
||||
TcpNetConnection connection = new TcpNetConnection(socket, true);
|
||||
TcpConnection connection = new TcpNetConnection(socket, true);
|
||||
connection = wrapConnection(connection);
|
||||
this.initializeConnection(connection, socket);
|
||||
this.taskExecutor.execute(connection);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
this.listening = false;
|
||||
if (this.active) {
|
||||
logger.error("Error on ServerSocket", e);
|
||||
|
||||
@@ -39,8 +39,6 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
public class TcpNioClientConnectionFactory extends
|
||||
AbstractClientConnectionFactory {
|
||||
|
||||
protected TcpNioConnection theConnection;
|
||||
|
||||
protected boolean usingDirectBuffers;
|
||||
|
||||
private Selector selector;
|
||||
@@ -63,7 +61,7 @@ public class TcpNioClientConnectionFactory extends
|
||||
* true, a new connection is returned; otherwise a single connection is
|
||||
* reused for all requests while the connection remains open.
|
||||
*/
|
||||
public TcpNioConnection getConnection() throws Exception {
|
||||
public TcpConnection getConnection() throws Exception {
|
||||
int n = 0;
|
||||
while (this.selector == null) {
|
||||
Thread.sleep(100);
|
||||
@@ -78,13 +76,14 @@ public class TcpNioClientConnectionFactory extends
|
||||
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(this.host, this.port));
|
||||
setSocketAttributes(socketChannel.socket());
|
||||
TcpNioConnection connection = new TcpNioConnection(socketChannel, false);
|
||||
connection.setUsingDirectBuffers(this.usingDirectBuffers);
|
||||
if (this.taskExecutor == null) {
|
||||
connection.setTaskExecutor(Executors.newSingleThreadExecutor());
|
||||
} else {
|
||||
connection.setTaskExecutor(this.taskExecutor);
|
||||
}
|
||||
initializeConnection(connection, socketChannel.socket());
|
||||
connection.setUsingDirectBuffers(this.usingDirectBuffers);
|
||||
TcpConnection wrappedConnection = wrapConnection(connection);
|
||||
initializeConnection(wrappedConnection, socketChannel.socket());
|
||||
socketChannel.configureBlocking(false);
|
||||
if (this.soTimeout > 0) {
|
||||
connection.setLastRead(System.currentTimeMillis());
|
||||
@@ -93,9 +92,9 @@ public class TcpNioClientConnectionFactory extends
|
||||
newChannels.add(socketChannel);
|
||||
selector.wakeup();
|
||||
if (!this.singleUse) {
|
||||
this.theConnection = connection;
|
||||
this.theConnection = wrappedConnection;
|
||||
}
|
||||
return connection;
|
||||
return wrappedConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,8 +43,6 @@ public class TcpNioConnection extends AbstractTcpConnection {
|
||||
|
||||
private final SocketChannel socketChannel;
|
||||
|
||||
private final boolean server;
|
||||
|
||||
private OutputStream channelOutputStream;
|
||||
|
||||
private PipedOutputStream pipedOutputStream;
|
||||
@@ -62,7 +60,7 @@ public class TcpNioConnection extends AbstractTcpConnection {
|
||||
private boolean active = true;
|
||||
|
||||
private long lastRead;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a TcpNetConnection for the SocketChannel.
|
||||
* @param socketChannel the socketChannel
|
||||
@@ -70,11 +68,15 @@ public class TcpNioConnection extends AbstractTcpConnection {
|
||||
* a result of an incoming request.
|
||||
*/
|
||||
public TcpNioConnection(SocketChannel socketChannel, boolean server) throws Exception {
|
||||
super(server);
|
||||
this.socketChannel = socketChannel;
|
||||
this.server = server;
|
||||
this.pipedInputStream = new PipedInputStream();
|
||||
this.pipedOutputStream = new PipedOutputStream(this.pipedInputStream);
|
||||
this.channelOutputStream = new ChannelOutputStream();
|
||||
getConnectionId();
|
||||
if (this.connectionId == null) {
|
||||
throw new Exception("Null id");
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
@@ -166,7 +168,6 @@ public class TcpNioConnection extends AbstractTcpConnection {
|
||||
|
||||
private synchronized void convertAndSend() throws IOException {
|
||||
if (this.pipedInputStream.available() <= 0) {
|
||||
System.err.println("NO WORK");
|
||||
return;
|
||||
}
|
||||
Message<?> message = null;
|
||||
@@ -175,7 +176,9 @@ public class TcpNioConnection extends AbstractTcpConnection {
|
||||
} catch (Exception e) {
|
||||
this.close();
|
||||
if (e instanceof SocketTimeoutException && this.singleUse) {
|
||||
logger.debug("Closing single use socket after timeout");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Closing single use socket after timeout " + this.connectionId);
|
||||
}
|
||||
} else {
|
||||
if (!(e instanceof SoftEndOfStreamException)) {
|
||||
logger.error("Read exception " +
|
||||
@@ -187,20 +190,30 @@ public class TcpNioConnection extends AbstractTcpConnection {
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* For single use sockets, we close after receipt if we are on the client
|
||||
* side, or the server side has no outbound adapter registered
|
||||
*/
|
||||
if (this.singleUse && (!this.server || this.sender == null)) {
|
||||
logger.debug("Closing single use socket after inbound message");
|
||||
this.close();
|
||||
}
|
||||
|
||||
try {
|
||||
if (message != null) {
|
||||
listener.onMessage(message);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Exception sending meeeage: " + message, e);
|
||||
if (e instanceof NoListenerException) {
|
||||
if (this.singleUse) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Closing single use channel after inbound message " + this.connectionId);
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
} else {
|
||||
logger.error("Exception sending meeeage: " + message, e);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* For single use sockets, we close after receipt if we are on the client
|
||||
* side, or the server side has no outbound adapter registered
|
||||
*/
|
||||
if (this.singleUse && this.server && this.sender == null) {
|
||||
logger.debug("Closing single use cbannel after inbound message " + this.connectionId);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +281,10 @@ public class TcpNioConnection extends AbstractTcpConnection {
|
||||
}
|
||||
|
||||
public String getConnectionId() {
|
||||
return SocketIoUtils.getSocketId(this.socketChannel.socket());
|
||||
if (this.connectionId == null) {
|
||||
this.connectionId = SocketIoUtils.getSocketId(this.socketChannel.socket());
|
||||
}
|
||||
return this.connectionId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,7 +342,7 @@ public class TcpNioConnection extends AbstractTcpConnection {
|
||||
doWrite(buffer);
|
||||
}
|
||||
|
||||
private void doWrite(ByteBuffer buffer) throws IOException {
|
||||
private synchronized void doWrite(ByteBuffer buffer) throws IOException {
|
||||
socketChannel.write(buffer);
|
||||
int remaining = buffer.remaining();
|
||||
if (remaining == 0) {
|
||||
|
||||
@@ -187,8 +187,9 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto
|
||||
private TcpNioConnection createTcpNioConnection(SocketChannel socketChannel) {
|
||||
try {
|
||||
TcpNioConnection connection = new TcpNioConnection(socketChannel, true);
|
||||
this.initializeConnection(connection, socketChannel.socket());
|
||||
connection.setUsingDirectBuffers(this.usingDirectBuffers);
|
||||
TcpConnection wrappedConnection = wrapConnection(connection);
|
||||
this.initializeConnection(wrappedConnection, socketChannel.socket());
|
||||
return connection;
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to establish new incoming connection", e);
|
||||
|
||||
@@ -372,6 +372,15 @@ its configuration specifies the number of threads.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="interceptor-factory-chain" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.ip.tcp.connection.InterceptorFactoryChain"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
@@ -297,6 +297,7 @@
|
||||
task-executor="externalTE"
|
||||
pool-size="321"
|
||||
using-direct-buffers="true"
|
||||
interceptor-factory-chain="interceptors"
|
||||
/>
|
||||
|
||||
<ip:tcp-connection-factory
|
||||
@@ -318,8 +319,11 @@
|
||||
task-executor="externalTE"
|
||||
pool-size="123"
|
||||
using-direct-buffers="true"
|
||||
interceptor-factory-chain="interceptors"
|
||||
/>
|
||||
|
||||
<bean id="interceptors" class="org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactoryChain" />
|
||||
|
||||
<bean id="serial" class="org.springframework.commons.serializer.java.JavaStreamingConverter" />
|
||||
|
||||
<ip:tcp-outbound-channel-adapter id="tcpNewOut1"
|
||||
@@ -337,6 +341,8 @@
|
||||
<ip:tcp-inbound-channel-adapter id="tcpNewIn2"
|
||||
channel="tcpChannel"
|
||||
connection-factory="server1" />
|
||||
|
||||
|
||||
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.integration.ip.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -436,6 +437,7 @@ public class ParserUnitTests {
|
||||
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
|
||||
assertEquals(321, dfa.getPropertyValue("poolSize"));
|
||||
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
|
||||
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -454,7 +456,8 @@ public class ParserUnitTests {
|
||||
assertEquals(true, dfa.getPropertyValue("singleUse"));
|
||||
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
|
||||
assertEquals(123, dfa.getPropertyValue("poolSize"));
|
||||
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
|
||||
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
|
||||
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
|
||||
|
||||
|
||||
<bean id="tcpIpUtils" class="org.springframework.integration.ip.util.SocketUtils" />
|
||||
|
||||
<bean id="serializer" class="org.springframework.commons.serializer.java.JavaStreamingConverter" />
|
||||
|
||||
<bean id="helloWorldInterceptors" class="org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactoryChain">
|
||||
<property name="interceptors">
|
||||
<array>
|
||||
<bean class="org.springframework.integration.ip.tcp.connection.HelloWorldInterceptorFactory"/>
|
||||
<bean class="org.springframework.integration.ip.tcp.connection.HelloWorldInterceptorFactory">
|
||||
<constructor-arg value="Hi"/>
|
||||
<constructor-arg value="planet!"/>
|
||||
</bean>
|
||||
</array>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<int-ip:tcp-connection-factory id="server"
|
||||
type="server"
|
||||
port="#{tcpIpUtils.findAvailableServerSocket(10000)}"
|
||||
input-converter="serializer"
|
||||
output-converter="serializer"
|
||||
using-nio="true"
|
||||
single-use="true"
|
||||
interceptor-factory-chain="helloWorldInterceptors"
|
||||
/>
|
||||
|
||||
<int-ip:tcp-connection-factory id="client"
|
||||
type="client"
|
||||
host="localhost"
|
||||
port="#{server.port}"
|
||||
single-use="true"
|
||||
so-timeout="100000"
|
||||
input-converter="serializer"
|
||||
output-converter="serializer"
|
||||
interceptor-factory-chain="helloWorldInterceptors"
|
||||
/>
|
||||
|
||||
<int:channel id="input" />
|
||||
|
||||
<int:channel id="replies">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int-ip:tcp-outbound-channel-adapter id="outboundClient"
|
||||
channel="input"
|
||||
connection-factory="client"/>
|
||||
|
||||
<int-ip:tcp-inbound-channel-adapter id="inboundClient"
|
||||
channel="replies"
|
||||
connection-factory="client"/>
|
||||
|
||||
<int-ip:tcp-inbound-channel-adapter id="inboundServer"
|
||||
channel="loop"
|
||||
connection-factory="server"/>
|
||||
|
||||
<int-ip:tcp-outbound-channel-adapter id="outboundServer"
|
||||
channel="loop"
|
||||
connection-factory="server"/>
|
||||
|
||||
<int:channel id="loop" />
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.ip.tcp;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class InterceptedSharedConnectionTests {
|
||||
|
||||
@Autowired
|
||||
AbstractApplicationContext ctx;
|
||||
|
||||
@Autowired
|
||||
@Qualifier(value="inboundServer")
|
||||
TcpReceivingChannelAdapter listener;
|
||||
|
||||
/**
|
||||
* Tests a loopback. The client-side outbound adapter sends a message over
|
||||
* a connection from the client connection factory; the server side
|
||||
* receives the message, puts in on a channel which is the input channel
|
||||
* for the outbound adapter that's sharing the connections. The response
|
||||
* comes back to an inbound adapter that is sharing the client's
|
||||
* connection and we verify we get the echo back as expected.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void test1() throws Exception {
|
||||
int n = 0;
|
||||
Object o = ctx.getBean("inboundServer");
|
||||
while (!listener.isListening()) {
|
||||
Thread.sleep(100);
|
||||
if (n++ > 100) {
|
||||
fail("Failed to listen");
|
||||
}
|
||||
}
|
||||
MessageChannel input = ctx.getBean("input", MessageChannel.class);
|
||||
input.send(MessageBuilder.withPayload("Test").build());
|
||||
QueueChannel replies = ctx.getBean("replies", QueueChannel.class);
|
||||
Message<?> message = replies.receive(10000);
|
||||
assertNotNull(message);
|
||||
assertEquals("Test", message.getPayload());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import org.springframework.integration.Message;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpListener;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -48,7 +47,7 @@ public class SharedConnectionTests {
|
||||
|
||||
@Autowired
|
||||
@Qualifier(value="inboundServer")
|
||||
TcpListener listener;
|
||||
TcpReceivingChannelAdapter listener;
|
||||
|
||||
/**
|
||||
* Tests a loopback. The client-side outbound adapter sends a message over
|
||||
|
||||
@@ -22,7 +22,11 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -34,10 +38,14 @@ import java.util.concurrent.Executors;
|
||||
import javax.net.SocketFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.commons.serializer.java.JavaStreamingConverter;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.ip.AbstractInternetProtocolReceivingChannelAdapter;
|
||||
import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.HelloWorldInterceptorFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactoryChain;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpNioServerConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.converter.ByteArrayCrLfConverter;
|
||||
@@ -577,6 +585,190 @@ public class TcpReceivingChannelAdapterTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNetInterceptors() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
AbstractServerConnectionFactory scf = new TcpNetServerConnectionFactory(port);
|
||||
interceptorsGuts(port, scf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNetSingleNoOutboundInterceptors() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
AbstractServerConnectionFactory scf = new TcpNetServerConnectionFactory(port);
|
||||
singleNoOutboundInterceptorsGuts(port, scf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNetSingleSharedInterceptors() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
AbstractServerConnectionFactory scf = new TcpNetServerConnectionFactory(port);
|
||||
singleSharedInterceptorsGuts(port, scf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNioInterceptors() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
AbstractServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
|
||||
interceptorsGuts(port, scf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNioSingleNoOutboundInterceptors() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
AbstractServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
|
||||
singleNoOutboundInterceptorsGuts(port, scf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNioSingleSharedInterceptors() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
AbstractServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
|
||||
singleSharedInterceptorsGuts(port, scf);
|
||||
}
|
||||
|
||||
private void interceptorsGuts(final int port,
|
||||
AbstractServerConnectionFactory scf) throws Exception {
|
||||
JavaStreamingConverter converter = new JavaStreamingConverter();
|
||||
scf.setInputConverter(converter);
|
||||
scf.setOutputConverter(converter);
|
||||
scf.setSingleUse(false);
|
||||
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
|
||||
adapter.setConnectionFactory(scf);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
scf.setInterceptorFactoryChain(fc);
|
||||
scf.setSoTimeout(10000);
|
||||
scf.start();
|
||||
int n = 0;
|
||||
while (!scf.isListening()) {
|
||||
Thread.sleep(100);
|
||||
if (n++ > 100) {
|
||||
fail("Failed to start listening");
|
||||
}
|
||||
}
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
Socket socket = SocketFactory.getDefault().createSocket("localhost", port);
|
||||
socket.setSoTimeout(10000);
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Test1");
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Test2");
|
||||
Message<?> message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
assertEquals("Test1", message.getPayload());
|
||||
message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
assertEquals("Test2", message.getPayload());
|
||||
}
|
||||
|
||||
private void singleNoOutboundInterceptorsGuts(final int port,
|
||||
AbstractServerConnectionFactory scf) throws Exception {
|
||||
JavaStreamingConverter converter = new JavaStreamingConverter();
|
||||
scf.setInputConverter(converter);
|
||||
scf.setOutputConverter(converter);
|
||||
scf.setSingleUse(true);
|
||||
scf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
scf.setInterceptorFactoryChain(fc);
|
||||
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
|
||||
adapter.setConnectionFactory(scf);
|
||||
scf.start();
|
||||
int n = 0;
|
||||
while (!scf.isListening()) {
|
||||
Thread.sleep(100);
|
||||
if (n++ > 100) {
|
||||
fail("Failed to start listening");
|
||||
}
|
||||
}
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
Socket socket = SocketFactory.getDefault().createSocket("localhost", port);
|
||||
socket.setSoTimeout(10000);
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Test1");
|
||||
socket = SocketFactory.getDefault().createSocket("localhost", port);
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Test2");
|
||||
Message<?> message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
// with single use, results may come back in a different order
|
||||
Set<Object> results = new HashSet<Object>();
|
||||
results.add(message.getPayload());
|
||||
message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
results.add(message.getPayload());
|
||||
assertTrue(results.contains("Test1"));
|
||||
assertTrue(results.contains("Test2"));
|
||||
}
|
||||
|
||||
private void singleSharedInterceptorsGuts(final int port,
|
||||
AbstractServerConnectionFactory scf) throws Exception {
|
||||
JavaStreamingConverter converter = new JavaStreamingConverter();
|
||||
scf.setInputConverter(converter);
|
||||
scf.setOutputConverter(converter);
|
||||
scf.setSingleUse(true);
|
||||
scf.setSoTimeout(60000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
scf.setInterceptorFactoryChain(fc);
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(scf);
|
||||
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
|
||||
adapter.setConnectionFactory(scf);
|
||||
scf.start();
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
int n = 0;
|
||||
while (!scf.isListening()) {
|
||||
Thread.sleep(100);
|
||||
if (n++ > 100) {
|
||||
fail("Failed to listen");
|
||||
}
|
||||
}
|
||||
Socket socket1 = SocketFactory.getDefault().createSocket("localhost", port);
|
||||
socket1.setSoTimeout(60000);
|
||||
new ObjectOutputStream(socket1.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket1.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket1.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket1.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket1.getOutputStream()).writeObject("Test1");
|
||||
|
||||
Socket socket2 = SocketFactory.getDefault().createSocket("localhost", port);
|
||||
socket2.setSoTimeout(60000);
|
||||
new ObjectOutputStream(socket2.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket2.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket2.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket2.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket2.getOutputStream()).writeObject("Test2");
|
||||
|
||||
Message<?> message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
handler.handleMessage(message);
|
||||
message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
handler.handleMessage(message);
|
||||
|
||||
assertEquals("Test1", new ObjectInputStream(socket1.getInputStream()).readObject());
|
||||
assertEquals("Test2", new ObjectInputStream(socket2.getInputStream()).readObject());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.ip.tcp;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -41,6 +42,9 @@ import org.springframework.integration.Message;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.HelloWorldInterceptorFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactoryChain;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpNioClientConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.converter.ByteArrayCrLfConverter;
|
||||
@@ -272,7 +276,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNio() throws Exception {
|
||||
public void newTestNioCrLf() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean done = new AtomicBoolean();
|
||||
@@ -827,7 +831,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
while (true) {
|
||||
Socket socket = server.accept();
|
||||
semaphore.release();
|
||||
byte[] b = new byte[8];
|
||||
byte[] b = new byte[9];
|
||||
readFully(socket.getInputStream(), b);
|
||||
b = ("Reply" + (i++) + "\r\n").getBytes();
|
||||
socket.getOutputStream().write(b);
|
||||
@@ -853,19 +857,267 @@ public class TcpSendingMessageHandlerTests {
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
for (int i = 100; i < 200; i++) {
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test" + i).build());
|
||||
int i = 0;
|
||||
try {
|
||||
for (i = 100; i < 200; i++) {
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test" + i).build());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail("Exception at " + i);
|
||||
}
|
||||
assertTrue(semaphore.tryAcquire(100, 20000, TimeUnit.MILLISECONDS));
|
||||
Set<String> replies = new HashSet<String>();
|
||||
for (int i = 100; i < 200; i++) {
|
||||
for (i = 100; i < 200; i++) {
|
||||
Message<?> mOut = channel.receive(20000);
|
||||
assertNotNull(mOut);
|
||||
replies.add(new String((byte[])mOut.getPayload()));
|
||||
}
|
||||
for (int i = 0; i < 100; i++) {
|
||||
for (i = 0; i < 100; i++) {
|
||||
assertTrue("Reply" + i + " missing", replies.remove("Reply" + i));
|
||||
}
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNetNegotiate() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean done = new AtomicBoolean();
|
||||
Executors.newSingleThreadExecutor().execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port);
|
||||
latch.countDown();
|
||||
Socket socket = server.accept();
|
||||
int i = 0;
|
||||
while (true) {
|
||||
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
|
||||
Object in;
|
||||
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
if (i == 0) {
|
||||
in = ois.readObject();
|
||||
// System.out.println(in);
|
||||
oos.writeObject("world!");
|
||||
ois = new ObjectInputStream(socket.getInputStream());
|
||||
oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
in = ois.readObject();
|
||||
// System.out.println(in);
|
||||
oos.writeObject("world!");
|
||||
ois = new ObjectInputStream(socket.getInputStream());
|
||||
oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
}
|
||||
in = ois.readObject();
|
||||
oos.writeObject("Reply" + (++i));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!done.get()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
|
||||
JavaStreamingConverter converter = new JavaStreamingConverter();
|
||||
ccf.setInputConverter(converter);
|
||||
ccf.setOutputConverter(converter);
|
||||
ccf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
ccf.setInterceptorFactoryChain(fc);
|
||||
ccf.start();
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(ccf);
|
||||
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
|
||||
adapter.setConnectionFactory(ccf);
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
assertNotNull(mOut);
|
||||
assertEquals("Reply1", mOut.getPayload());
|
||||
mOut = channel.receive(10000);
|
||||
assertNotNull(mOut);
|
||||
assertEquals("Reply2", mOut.getPayload());
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNioNegotiate() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean done = new AtomicBoolean();
|
||||
Executors.newSingleThreadExecutor().execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port);
|
||||
latch.countDown();
|
||||
Socket socket = server.accept();
|
||||
int i = 0;
|
||||
while (true) {
|
||||
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
|
||||
Object in;
|
||||
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
if (i == 0) {
|
||||
in = ois.readObject();
|
||||
// System.out.println(in);
|
||||
oos.writeObject("world!");
|
||||
ois = new ObjectInputStream(socket.getInputStream());
|
||||
oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
}
|
||||
in = ois.readObject();
|
||||
oos.writeObject("Reply" + (++i));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!done.get()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
AbstractConnectionFactory ccf = new TcpNioClientConnectionFactory("localhost", port);
|
||||
JavaStreamingConverter converter = new JavaStreamingConverter();
|
||||
ccf.setInputConverter(converter);
|
||||
ccf.setOutputConverter(converter);
|
||||
ccf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[] {new HelloWorldInterceptorFactory()});
|
||||
ccf.setInterceptorFactoryChain(fc);
|
||||
ccf.start();
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(ccf);
|
||||
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
|
||||
adapter.setConnectionFactory(ccf);
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
assertNotNull(mOut);
|
||||
assertEquals("Reply1", mOut.getPayload());
|
||||
mOut = channel.receive(10000);
|
||||
assertNotNull(mOut);
|
||||
assertEquals("Reply2", mOut.getPayload());
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNetNegotiateSingleNoListen() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean done = new AtomicBoolean();
|
||||
Executors.newSingleThreadExecutor().execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port);
|
||||
latch.countDown();
|
||||
Socket socket = server.accept();
|
||||
int i = 0;
|
||||
while (true) {
|
||||
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
|
||||
Object in;
|
||||
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
if (i == 0) {
|
||||
in = ois.readObject();
|
||||
// System.out.println(in);
|
||||
oos.writeObject("world!");
|
||||
ois = new ObjectInputStream(socket.getInputStream());
|
||||
oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
in = ois.readObject();
|
||||
// System.out.println(in);
|
||||
oos.writeObject("world!");
|
||||
ois = new ObjectInputStream(socket.getInputStream());
|
||||
oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
}
|
||||
in = ois.readObject();
|
||||
oos.writeObject("Reply" + (++i));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!done.get()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
|
||||
JavaStreamingConverter converter = new JavaStreamingConverter();
|
||||
ccf.setInputConverter(converter);
|
||||
ccf.setOutputConverter(converter);
|
||||
ccf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
ccf.setInterceptorFactoryChain(fc);
|
||||
ccf.setSingleUse(true);
|
||||
ccf.start();
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(ccf);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newTestNioNegotiateSingleNoListen() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean done = new AtomicBoolean();
|
||||
Executors.newSingleThreadExecutor().execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port);
|
||||
latch.countDown();
|
||||
Socket socket = server.accept();
|
||||
int i = 0;
|
||||
while (true) {
|
||||
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
|
||||
Object in;
|
||||
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
if (i == 0) {
|
||||
in = ois.readObject();
|
||||
// System.out.println(in);
|
||||
oos.writeObject("world!");
|
||||
ois = new ObjectInputStream(socket.getInputStream());
|
||||
oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
in = ois.readObject();
|
||||
// System.out.println(in);
|
||||
oos.writeObject("world!");
|
||||
ois = new ObjectInputStream(socket.getInputStream());
|
||||
oos = new ObjectOutputStream(socket.getOutputStream());
|
||||
}
|
||||
in = ois.readObject();
|
||||
oos.writeObject("Reply" + (++i));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!done.get()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
AbstractConnectionFactory ccf = new TcpNioClientConnectionFactory("localhost", port);
|
||||
JavaStreamingConverter converter = new JavaStreamingConverter();
|
||||
ccf.setInputConverter(converter);
|
||||
ccf.setOutputConverter(converter);
|
||||
ccf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
ccf.setInterceptorFactoryChain(fc);
|
||||
ccf.setSingleUse(true);
|
||||
ccf.start();
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(ccf);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
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.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.core.MessageBuilder;
|
||||
import org.springframework.integration.ip.tcp.connection.AbstractTcpConnectionInterceptor;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public class HelloWorldInterceptor extends AbstractTcpConnectionInterceptor {
|
||||
|
||||
Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private boolean negotiated;
|
||||
|
||||
private Semaphore negotiationSemaphore = new Semaphore(0);
|
||||
|
||||
private long timeout = 10000;
|
||||
|
||||
private String hello = "Hello";
|
||||
|
||||
private String world = "world!";
|
||||
|
||||
public HelloWorldInterceptor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hello
|
||||
* @param world
|
||||
*/
|
||||
public HelloWorldInterceptor(String hello, String world) {
|
||||
super();
|
||||
this.hello = hello;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(Message<?> message) {
|
||||
if (!this.negotiated) {
|
||||
Object payload = message.getPayload();
|
||||
if (this.isServer()) {
|
||||
if (payload.equals(hello)) {
|
||||
try {
|
||||
logger.debug("sending " + this.world);
|
||||
super.send(MessageBuilder.withPayload(world).build());
|
||||
this.negotiated = true;
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
throw new MessagingException("Negotiation error", e);
|
||||
}
|
||||
} else {
|
||||
throw new MessagingException("Negotiation error, expected '" + hello +
|
||||
"' received '" + payload + "'");
|
||||
}
|
||||
} else {
|
||||
logger.debug("received " + payload);
|
||||
if (payload.equals(world)) {
|
||||
this.negotiated = true;
|
||||
this.negotiationSemaphore.release();
|
||||
} else {
|
||||
throw new MessagingException("Negotiation error - expected '" + world +
|
||||
"' received " + payload);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Message<?> message) throws Exception {
|
||||
if (!this.negotiated) {
|
||||
if (!this.isServer()) {
|
||||
logger.debug("Sending " + hello);
|
||||
super.send(MessageBuilder.withPayload(hello).build());
|
||||
this.negotiationSemaphore.tryAcquire(this.timeout, TimeUnit.MILLISECONDS);
|
||||
if (!this.negotiated) {
|
||||
throw new MessagingException("Negotiation error");
|
||||
}
|
||||
}
|
||||
}
|
||||
super.send(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.ip.tcp.connection;
|
||||
|
||||
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactory;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
public class HelloWorldInterceptorFactory extends
|
||||
TcpConnectionInterceptorFactory {
|
||||
|
||||
private String hello = "Hello";
|
||||
|
||||
private String world = "world!";
|
||||
|
||||
public HelloWorldInterceptorFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hello
|
||||
* @param world
|
||||
*/
|
||||
public HelloWorldInterceptorFactory(String hello, String world) {
|
||||
this.hello = hello;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TcpConnectionInterceptor getInterceptor() {
|
||||
return new HelloWorldInterceptor(hello, world);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -64,7 +64,7 @@ public class TcpNioConnectionTests {
|
||||
});
|
||||
assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));
|
||||
try {
|
||||
TcpNioConnection connection = factory.getConnection();
|
||||
TcpConnection connection = factory.getConnection();
|
||||
connection.send(MessageBuilder.withPayload(new byte[1000000]).build());
|
||||
} catch (Exception e) {
|
||||
assertTrue("Expected SocketTimeoutException, got " + e.getClass().getSimpleName() +
|
||||
@@ -97,7 +97,7 @@ public class TcpNioConnectionTests {
|
||||
});
|
||||
assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));
|
||||
try {
|
||||
TcpNioConnection connection = factory.getConnection();
|
||||
TcpConnection connection = factory.getConnection();
|
||||
connection.send(MessageBuilder.withPayload("Test").build());
|
||||
int n = 0;
|
||||
while (connection.isOpen()) {
|
||||
@@ -108,7 +108,7 @@ public class TcpNioConnectionTests {
|
||||
}
|
||||
assertTrue(!connection.isOpen());
|
||||
} catch (Exception e) {
|
||||
fail("Unexptected exception " + e);
|
||||
fail("Unexpected exception " + e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user