FileDocCategorySizeDatePackage
FramedMessageOutputStream.javaAPI DocExample11631Tue May 29 16:57:10 BST 2007com.sun.xml.ws.transport.tcp.io

FramedMessageOutputStream

public final class FramedMessageOutputStream extends OutputStream implements com.sun.xml.ws.transport.tcp.pool.LifeCycle
author
Alexey Stashok

Fields Summary
private static final int
HEADER_BUFFER_SIZE
private boolean
useDirectBuffer
private ByteBuffer
outputBuffer
private SocketChannel
socketChannel
private int
frameNumber
private int
frameSize
private boolean
isFlushLast
private int
channelId
private int
messageId
private int
contentId
private Map
contentProps
private int
payloadlengthLength
private boolean
isDirectMode
is message framed or direct mode is used
private final ByteBuffer
headerBuffer
private final ByteBuffer[]
frame
private long
sentMessageLength
could be useful for debug reasons
Constructors Summary
public FramedMessageOutputStream()

    
      
        this(TCPConstants.DEFAULT_FRAME_SIZE, TCPConstants.DEFAULT_USE_DIRECT_BUFFER);
    
public FramedMessageOutputStream(int frameSize)

        this(frameSize, TCPConstants.DEFAULT_USE_DIRECT_BUFFER);
    
public FramedMessageOutputStream(int frameSize, boolean useDirectBuffer)

        this.useDirectBuffer = useDirectBuffer;
        headerBuffer = ByteBufferFactory.allocateView(frameSize, useDirectBuffer);
        setFrameSize(frameSize);
    
Methods Summary
public voidactivate()

    
public voidaddAllContentProperties(java.util.Map properties)

        this.contentProps.putAll(properties);
    
private intcalcPayloadSizeToSend(int readyBytesToSend)

        int payloadLength = outputBuffer.remaining();
        if (readyBytesToSend > frameSize) {
            payloadLength -= (readyBytesToSend - frameSize);
        }
        
        return payloadLength;
    
public voidclose()

    
private voidflushBuffer()

        final int payloadLength = outputBuffer.remaining();
        if (!isDirectMode) {
            headerBuffer.clear();
            // Write channel-id
            int frameMessageIdHighValue = DataInOutUtils.writeInt4(headerBuffer, channelId, 0, false);
            int frameMessageIdPosition = headerBuffer.position();
            boolean isFrameWithParameters = FrameType.isFrameContainsParams(messageId) && frameNumber == 0;

            // Write message-id without counting with possible chunking
            int highValue = DataInOutUtils.writeInt4(headerBuffer, messageId, frameMessageIdHighValue, !isFrameWithParameters);
            
            if (isFrameWithParameters) {
                // If required - serialize frame content-id, content-parameters
                // Write content-id
                highValue = DataInOutUtils.writeInt4(headerBuffer, contentId, highValue, false);
                
                final int propsCount = contentProps.size();
                // Write number-of-parameters
                highValue = DataInOutUtils.writeInt4(headerBuffer, propsCount, highValue, propsCount == 0);
                
                for(Map.Entry<Integer, String> entry : contentProps.entrySet()) {
                    final String value = entry.getValue();
                    byte[] valueBytes = value.getBytes(TCPConstants.UTF8);
                    // Write parameter-id
                    highValue = DataInOutUtils.writeInt4(headerBuffer, entry.getKey(), highValue, false);
                    // Write parameter-value buffer length
                    DataInOutUtils.writeInt4(headerBuffer, valueBytes.length, highValue, true);
                    // Write parameter-value
                    headerBuffer.put(valueBytes);
                    highValue = 0;
                }
            }
            
            int readyBytesToSend = headerBuffer.position() + payloadlengthLength + payloadLength;
            
            if (messageId == FrameType.MESSAGE) {
                // If message will be chunked - update message-id
                updateMessageIdIfRequired(frameMessageIdPosition, 
                        frameMessageIdHighValue, 
                        isFlushLast && readyBytesToSend <= frameSize);
            }

            final int sendingPayloadLength = calcPayloadSizeToSend(readyBytesToSend);

            // Write payload-length
            DataInOutUtils.writeInt8(headerBuffer, sendingPayloadLength);
            headerBuffer.flip();
            final int payloadLimit = outputBuffer.limit();
            if (sendingPayloadLength < payloadLength) {
                // check to change for outputBuffer.limit(sendingPayloadLength);
                outputBuffer.limit(outputBuffer.limit() - (payloadLength - sendingPayloadLength));
            }
            
            OutputWriter.flushChannel(socketChannel, frame);
            outputBuffer.limit(payloadLimit);
            sentMessageLength += sendingPayloadLength;
            frameNumber++;
        } else {
            OutputWriter.flushChannel(socketChannel, outputBuffer);
        }
    
private voidflushFrame()

        outputBuffer.flip();
        flushBuffer();
        outputBuffer.compact();
    
public voidflushLast()

        if (!isFlushLast) {
            outputBuffer.flip();
            isFlushLast = true;
            
            do {
                flushBuffer();
            } while(outputBuffer.hasRemaining());
            outputBuffer.clear();
        }
    
private voidformFrameBufferArray()

        frame[0] = headerBuffer;
        frame[1] = outputBuffer;
    
public booleanisDirectMode()

        return isDirectMode;
    
public voidpassivate()

        reset();
        socketChannel = null;
    
public voidreset()

        outputBuffer.clear();
        headerBuffer.clear();
        messageId = -1;
        contentId = -1;
        contentProps.clear();
        frameNumber = 0;
        isFlushLast = false;
        sentMessageLength = 0;
    
public voidsetChannelId(int channelId)

        this.channelId = channelId;
    
public voidsetContentId(int contentId)

        this.contentId = contentId;
    
public voidsetContentProperty(int key, java.lang.String value)

        this.contentProps.put(key, value);
    
public voidsetDirectMode(boolean isDirectMode)

        reset();
        this.isDirectMode = isDirectMode;
    
public voidsetFrameSize(int frameSize)

        this.frameSize = frameSize;
        payloadlengthLength = (int) Math.ceil(Math.log(frameSize) / Math.log(2));
        outputBuffer = ByteBufferFactory.allocateView(frameSize, useDirectBuffer);
        formFrameBufferArray();
    
public voidsetMessageId(int messageId)

        this.messageId = messageId;
    
public voidsetSocketChannel(java.nio.channels.SocketChannel socketChannel)

        this.socketChannel = socketChannel;
    
private voidupdateMessageIdIfRequired(int frameMessageIdPosition, int frameMessageIdHighValue, boolean isLastFrame)

        
        int frameMessageId;
        if (isLastFrame) {
            if (frameNumber != 0) {
                frameMessageId = FrameType.MESSAGE_END_CHUNK;
            } else {
                // Serialized message-id is correct
                return;
            }
        } else if (frameNumber == 0) {
            frameMessageId = FrameType.MESSAGE_START_CHUNK;
        } else {
            frameMessageId = FrameType.MESSAGE_CHUNK;
        }
        
        // merge message-id Integer4 data with next value
        if (frameMessageIdHighValue != 0) {
            // merge message-id as lower octet nibble
            headerBuffer.put(frameMessageIdPosition, (byte) ((frameMessageIdHighValue & 0x70) | frameMessageId));
        } else {
            // merge message-id as higher octet nibble
            int value = headerBuffer.get(frameMessageIdPosition);
            headerBuffer.put(frameMessageIdPosition, (byte) ((frameMessageId << 4) | (value & 0xF)));
        }
    
public voidwrite(int data)

        if (!outputBuffer.hasRemaining()) {
            flushFrame();
        }
        
        outputBuffer.put((byte) data);
    
public voidwrite(byte[] data, int offset, int size)

        while(size > 0) {
            final int bytesToWrite = Math.min(size, outputBuffer.remaining());
            outputBuffer.put(data, offset, bytesToWrite);
            size -= bytesToWrite;
            offset += bytesToWrite;
            if (!outputBuffer.hasRemaining() && size > 0) {
                flushFrame();
            }
        }