INT-1486 polish; rename byte array 'serializers' and all test usage

This commit is contained in:
Gary Russell
2010-09-28 22:25:04 -04:00
parent 4ae4b5d4d7
commit b339157a34
23 changed files with 172 additions and 951 deletions

View File

@@ -45,7 +45,7 @@ public abstract class AbstractClientConnectionFactory extends AbstractConnection
}
/**
* Transfers attributes such as converters, singleUse etc to a new connection.
* Transfers attributes such as (de)serializers, singleUse etc to a new connection.
* When the connection factory has a reference to a TCPListener (to read
* responses), or for single use connections, the connection is executed.
* Single use connections need to read from the connection in order to

View File

@@ -27,7 +27,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.commons.serializer.Deserializer;
import org.springframework.commons.serializer.Serializer;
import org.springframework.context.SmartLifecycle;
import org.springframework.integration.ip.tcp.converter.ByteArrayCrLfConverter;
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
import org.springframework.util.Assert;
/**
@@ -68,9 +68,9 @@ public abstract class AbstractConnectionFactory
protected Executor taskExecutor;
protected Deserializer<?> deserializer = new ByteArrayCrLfConverter();
protected Deserializer<?> deserializer = new ByteArrayCrLfSerializer();
protected Serializer<?> serializer = new ByteArrayCrLfConverter();
protected Serializer<?> serializer = new ByteArrayCrLfSerializer();
protected TcpMessageMapper mapper = new TcpMessageMapper();

View File

@@ -60,7 +60,7 @@ public abstract class AbstractServerConnectionFactory extends AbstractConnection
}
/**
* Transfers attributes such as converters, singleUse etc to a new connection.
* Transfers attributes such as (de)serializer, singleUse etc to a new connection.
* For single use sockets, enforces a socket timeout (default 10 seconds).
* @param connection The new connection.
* @param socket The new socket.

View File

@@ -23,7 +23,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.commons.serializer.Deserializer;
import org.springframework.commons.serializer.Serializer;
import org.springframework.integration.ip.tcp.converter.AbstractByteArrayStreamingConverter;
import org.springframework.integration.ip.tcp.serializer.AbstractByteArraySerializer;
import org.springframework.util.Assert;
/**
@@ -86,7 +86,7 @@ public abstract class AbstractTcpConnection implements TcpConnection {
Assert.notNull(mapper, this.getClass().getName() + " Mapper may not be null");
this.mapper = mapper;
if (this.serializer != null &&
!(this.serializer instanceof AbstractByteArrayStreamingConverter)) {
!(this.serializer instanceof AbstractByteArraySerializer)) {
mapper.setStringToBytes(false);
}
}
@@ -119,7 +119,7 @@ public abstract class AbstractTcpConnection implements TcpConnection {
*/
public void setSerializer(Serializer<?> serializer) {
this.serializer = serializer;
if (!(serializer instanceof AbstractByteArrayStreamingConverter)) {
if (!(serializer instanceof AbstractByteArraySerializer)) {
this.mapper.setStringToBytes(false);
}
}

View File

@@ -25,7 +25,7 @@ import org.springframework.integration.Message;
/**
* An abstraction over {@link Socket} and {@link SocketChannel} that
* sends {@link Message} objects by converting the payload
* sends {@link Message} objects by serializing the payload
* and streaming it to the destination. Requires a {@link TcpListener}
* to receive incoming messages.
*
@@ -53,7 +53,7 @@ public interface TcpConnection extends Runnable {
public void send(Message<?> message) throws Exception;
/**
* Uses the input converter to obtain the message payload
* Uses the deserializer to obtain the message payload
* from the connection's input stream.
* @return The payload
* @throws Exception

View File

@@ -88,7 +88,7 @@ public class TcpMessageMapper implements
}
else {
throw new MessageHandlingException(message,
"When using a byte array streaming converter, the socket mapper expects " +
"When using a byte array serializer, the socket mapper expects " +
"either a byte array or String payload, but received: " + payload.getClass());
}
return bytes;

View File

@@ -19,9 +19,10 @@ package org.springframework.integration.ip.tcp.connection;
import java.net.Socket;
import java.net.SocketTimeoutException;
import org.springframework.commons.serializer.Deserializer;
import org.springframework.integration.Message;
import org.springframework.integration.ip.tcp.SocketIoUtils;
import org.springframework.integration.ip.tcp.converter.SoftEndOfStreamException;
import org.springframework.integration.ip.tcp.serializer.SoftEndOfStreamException;
/**
* A TcpConnection that uses and underlying {@link Socket}.
@@ -88,7 +89,7 @@ public class TcpNetConnection extends AbstractTcpConnection {
* If there is no listener, and this connection is not for single use,
* this method exits. When there is a listener, the method runs in a
* loop reading input from the connections's stream, data is converted
* to an object using the {@link InputStreamingConverter} and the listener's
* to an object using the {@link Deserializer} and the listener's
* {@link TcpListener#onMessage(Message)} method is called. For single use
* connections with no listener, the socket is closed after its timeout
* expires. If data is received on a single use socket with no listener,

View File

@@ -31,7 +31,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.integration.Message;
import org.springframework.integration.ip.tcp.SocketIoUtils;
import org.springframework.integration.ip.tcp.converter.SoftEndOfStreamException;
import org.springframework.integration.ip.tcp.serializer.SoftEndOfStreamException;
/**
* A TcpConnection that uses and underlying {@link SocketChannel}.

View File

@@ -1,67 +0,0 @@
/*
* 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.converter;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.commons.serializer.Deserializer;
import org.springframework.commons.serializer.Serializer;
/**
* Base class for streaming converters that convert to/from a byte array.
*
* @author Gary Russell
* @since 2.0
*
*/
public abstract class AbstractByteArrayStreamingConverter implements
Serializer<byte[]>,
Deserializer<byte[]> {
protected int maxMessageSize = 2048;
protected Log logger = LogFactory.getLog(this.getClass());
/**
* The maximum supported message size for this converter.
* Default 2048.
* @return The max message size.
*/
public int getMaxMessageSize() {
return maxMessageSize;
}
/**
* The maximum supported message size for this converter.
* Default 2048.
* @param maxMessageSize The max message size.
*/
public void setMaxMessageSize(int maxMessageSize) {
this.maxMessageSize = maxMessageSize;
}
protected void checkClosure(int bite) throws IOException {
if (bite < 0) {
logger.debug("Socket closed");
throw new IOException("Socket closed");
}
}
}

View File

@@ -1,75 +0,0 @@
/*
* 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.converter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Converts data in an InputStream to a byte[]; data is terminated by \r\n
* (not included in resulting byte[]).
* Writes a byte[] to an OutputStream and adds \r\n.
*
* @author Gary Russell
* @since 2.0
*/
public class ByteArrayCrLfConverter extends AbstractByteArrayStreamingConverter {
/**
* Converts the data in the inputstream to a byte[]. Data must be terminated
* by CRLF (\r\n). Throws a {@link SoftEndOfStreamException} if the stream
* is closed immediately after the \r\n (i.e. no data is in the process of
* being read).
*/
public byte[] deserialize(InputStream inputStream) throws IOException {
byte[] buffer = new byte[this.maxMessageSize];
int n = 0;
int bite;
if (logger.isDebugEnabled())
logger.debug("Available to read:" + inputStream.available());
while (true) {
bite = inputStream.read();
// logger.debug("Read:" + (char) bite);
if (bite < 0 && n == 0) {
throw new SoftEndOfStreamException("Stream closed between payloads");
}
checkClosure(bite);
if (n > 0 && bite == '\n' && buffer[n-1] == '\r')
break;
buffer[n++] = (byte) bite;
if (n >= this.maxMessageSize) {
throw new IOException("CRLF not found before max message length: "
+ this.maxMessageSize);
}
};
byte[] assembledData = new byte[n-1];
System.arraycopy(buffer, 0, assembledData, 0, n-1);
return assembledData;
}
/**
* Writes the byte[] to the stream and appends \r\n.
*/
public void serialize(byte[] bytes, OutputStream outputStream) throws IOException {
outputStream.write(bytes);
outputStream.write('\r');
outputStream.write('\n');
outputStream.flush();
}
}

View File

@@ -1,113 +0,0 @@
/*
* 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.converter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Converts data in an InputStream to a byte[]; data is preceded by
* a 4 byte binary length (network byte order,
* not included in resulting byte[]).
* Writes a byte[] to an OutputStream after a 4 byte binary length.\
* The length field contains the length of data following the length
* field.
* (network byte order).
*
* @author Gary Russell
* @since 2.0
*/
public class ByteArrayLengthHeaderConverter extends AbstractByteArrayStreamingConverter {
private Log logger = LogFactory.getLog(this.getClass());
/**
* Reads a 4 byte length from the stream and then reads that length
* from the stream and returns the data in a byte[]. Throws an
* IOException if the length field exceeds the maxMessageSize.
* Throws a {@link SoftEndOfStreamException} if the stream
* is closed between messages.
*/
public byte[] deserialize(InputStream inputStream) throws IOException {
byte[] lengthPart = new byte[4];
int status = read(inputStream, lengthPart, true);
if (status < 0) {
throw new SoftEndOfStreamException("Stream closed between payloads");
}
int messageLength = ByteBuffer.wrap(lengthPart).getInt();
if (logger.isDebugEnabled()) {
logger.debug("Message length is " + messageLength);
}
if (messageLength > this.maxMessageSize) {
throw new IOException("Message length " + messageLength +
" exceeds max message length: " + this.maxMessageSize);
}
byte[] messagePart = new byte[messageLength];
read(inputStream, messagePart, false);
return messagePart;
}
/**
* Writes the byte[] to the output stream, preceded by a 4 byte
* length in network byte order (big endian).
*/
public void serialize(byte[] bytes, OutputStream outputStream) throws IOException {
ByteBuffer lengthPart = ByteBuffer.allocate(4);
lengthPart.putInt(bytes.length);
outputStream.write(lengthPart.array());
outputStream.write(bytes);
outputStream.flush();
}
/**
* Reads data from the socket and puts the data in buffer. Blocks until
* buffer is full or a socket timeout occurs.
* @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
*/
protected int read(InputStream inputStream, byte[] buffer, boolean header)
throws IOException {
int lengthRead = 0;
int needed = buffer.length;
while (lengthRead < needed) {
int len;
len = inputStream.read(buffer, lengthRead,
needed - lengthRead);
if (len < 0 && header && lengthRead == 0) {
return len;
}
if (len < 0) {
throw new IOException("Stream closed after " + lengthRead + " of " + needed);
}
lengthRead += len;
if (logger.isDebugEnabled()) {
logger.debug("Read " + len + " bytes, buffer is now at " +
lengthRead + " of " +
needed);
}
}
return 0;
}
}

View File

@@ -1,80 +0,0 @@
/*
* 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.converter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.springframework.integration.mapping.MessageMappingException;
/**
* Converts data in an InputStream to a byte[]; data is prefixed by &lt;stx&gt; and
* terminated by &lt;etx&gt; (not included in resulting byte[]).
* Writes a byte[] to an OutputStream and prefixed by &lt;stx&gt; terminated by &lt;etx&gt;
*
* @author Gary Russell
* @since 2.0
*/
public class ByteArrayStxEtxConverter extends AbstractByteArrayStreamingConverter {
public static final int STX = 0x02;
public static final int ETX = 0x03;
/**
* Converts the data in the inputstream to a byte[]. Data must be prefixed
* with an ASCII STX character, and terminated with an ASCII ETX character.
* Throws a {@link SoftEndOfStreamException} if the stream
* is closed immediately before the STX (i.e. no data is in the process of
* being read).
*
*/
public byte[] deserialize(InputStream inputStream) throws IOException {
int bite = inputStream.read();
if (bite < 0) {
throw new SoftEndOfStreamException("Stream closed between payloads");
}
if (bite != STX)
throw new MessageMappingException("Expected STX to begin message");
byte[] buffer = new byte[this.maxMessageSize];
int n = 0;
while ((bite = inputStream.read()) != ETX) {
checkClosure(bite);
buffer[n++] = (byte) bite;
if (n >= this.maxMessageSize) {
throw new IOException("ETX not found before max message length: "
+ this.maxMessageSize);
}
}
byte[] assembledData = new byte[n];
System.arraycopy(buffer, 0, assembledData, 0, n);
return assembledData;
}
/**
* Writes the byte[] to the stream, prefixed by an ASCII STX character and
* terminated with an ASCII ETX character.
*/
public void serialize(byte[] bytes, OutputStream outputStream) throws IOException {
outputStream.write(STX);
outputStream.write(bytes);
outputStream.write(ETX);
outputStream.flush();
}
}

View File

@@ -1,41 +0,0 @@
/*
* 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.converter;
import java.io.IOException;
/**
* Used to communicate that a stream has closed, but between logical
* messages.
*
* @author Gary Russell
* @since 2.0
*
*/
public class SoftEndOfStreamException extends IOException {
private static final long serialVersionUID = 7309907445617226978L;
public SoftEndOfStreamException() {
super();
}
public SoftEndOfStreamException(String message) {
super(message);
}
}

View File

@@ -1,6 +0,0 @@
/**
* Byte array converters for putting some protocol on the
* wire so we can delimit incoming messages.
*/
package org.springframework.integration.ip.tcp.converter;

View File

@@ -299,7 +299,7 @@ the factory, the connection will be closed after a response is received.
</xsd:appinfo>
<xsd:documentation>
A Serializer that converts message payloads to/from output streams/input streams
associated with the connection. Default is ByteArrayCrLfConverter. Serializer and Deserializer
associated with the connection. Default is ByteArrayCrLfSerializer. Serializer and Deserializer
would normally be the same but this is not required.
</xsd:documentation>
</xsd:annotation>
@@ -313,7 +313,7 @@ would normally be the same but this is not required.
</xsd:appinfo>
<xsd:documentation>
A Deserializer that converts message payloads to/from output streams/input streams
associated with the connection. Default is ByteArrayCrLfConverter. Serializer and Deserializer
associated with the connection. Default is ByteArrayCrLfSerializer. Serializer and Deserializer
would normally be the same but this is not required.
</xsd:documentation>
</xsd:annotation>