org.springframework.integration.ip.tcp.converter.ByteArrayLengthHeaderConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.integration.ip.tcp.converter.ByteArrayLengthHeaderConverter.java

Source

/*
 * 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
 *
 */
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[] convert(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 convert(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;
    }

}