com.sun.xml.ws.transport.tcp.io.FramedMessageInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of webservices-osgi Show documentation
Show all versions of webservices-osgi Show documentation
Metro Web Services Runtime OSGi Bundle
The newest version!
/*
* Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package com.sun.xml.ws.transport.tcp.io;
import com.sun.xml.ws.transport.tcp.pool.LifeCycle;
import com.sun.xml.ws.transport.tcp.resources.MessagesMessages;
import com.sun.xml.ws.transport.tcp.util.FrameType;
import com.sun.xml.ws.transport.tcp.util.SelectorFactory;
import com.sun.xml.ws.transport.tcp.util.TCPConstants;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Stream wrapper around a ByteBuffer
*/
public final class FramedMessageInputStream extends InputStream implements LifeCycle {
private static final Logger logger = Logger.getLogger(
com.sun.xml.ws.transport.tcp.util.TCPConstants.LoggingDomain + ".streams");
private ByteBuffer byteBuffer;
private SocketChannel socketChannel;
/**
* The time to wait before timing out when reading bytes
*/
final private static int READ_TIMEOUT = 30000;
/**
* Number of times to retry before return EOF
*/
final static int READ_TRY = 10;
private final int[] headerTmpArray = new int[2];
/** is message framed or direct mode is used */
private boolean isDirectMode;
private int frameSize;
private int frameBytesRead;
private boolean isLastFrame;
private int currentFrameDataSize; // for last frame actual data size could be smaller than frame size
private int channelId;
private int contentId;
private int messageId;
private final Map contentProps = new HashMap<>(8);
private boolean isReadingHeader;
/**
* could be useful for debug reasons
*/
private long receivedMessageLength;
// ------------------------------------------------- Constructor -------//
public FramedMessageInputStream() {
this(TCPConstants.DEFAULT_FRAME_SIZE);
}
public FramedMessageInputStream(int frameSize) {
setFrameSize(frameSize);
}
// ---------------------------------------------------------------------//
public void setSocketChannel(final SocketChannel socketChannel){
this.socketChannel = socketChannel;
}
public int getChannelId() {
return channelId;
}
public int getMessageId() {
return messageId;
}
public int getContentId() {
return contentId;
}
public Map getContentProperties() {
return contentProps;
}
public boolean isDirectMode() {
return isDirectMode;
}
public void setDirectMode(final boolean isDirectMode) {
reset();
this.isDirectMode = isDirectMode;
}
public void setFrameSize(final int frameSize) {
this.frameSize = frameSize;
}
public void setByteBuffer(final ByteBuffer byteBuffer) {
this.byteBuffer = byteBuffer;
}
/**
* Return the available bytes
* @return the wrapped byteBuffer.remaining()
*/
@Override
public int available() {
return remaining();
}
/**
* Close this stream.
*/
@Override
public void close() {
}
/**
* Return true if mark is supported.
*/
@Override
public boolean markSupported() {
return false;
}
/**
* Read the first byte from the wrapped ByteBuffer
.
*/
@Override
public int read() {
if (!isDirectMode) {
if (isLastFrame && frameBytesRead >= currentFrameDataSize) {
// check if last frame and there is no data
return -1;
}
int eof = 0;
if (!byteBuffer.hasRemaining()) {
eof = readFromChannel();
}
if (eof == -1 || readFrameHeaderIfRequired() == -1) {
return -1;
}
if (byteBuffer.hasRemaining()) {
frameBytesRead++;
receivedMessageLength++;
return byteBuffer.get() & 0xff;
}
return read();
} else {
if (!byteBuffer.hasRemaining()) {
int eof = readFromChannel();
if (eof == -1) {
return -1;
}
}
return byteBuffer.get() & 0xff;
}
}
/**
* Read the bytes from the wrapped ByteBuffer
.
*/
@Override
public int read(final byte[] b) {
return (read(b, 0, b.length));
}
/**
* Read the first byte of the wrapped ByteBuffer
.
*/
@Override
public int read(final byte[] b, final int offset, int length) {
if (!isDirectMode) {
if (isLastFrame && frameBytesRead >= currentFrameDataSize) {
// check if last frame and there is no data
return -1;
}
int eof = 0;
if (!byteBuffer.hasRemaining()) {
eof = readFromChannel();
}
if (eof == -1 || readFrameHeaderIfRequired() == -1) {
return -1;
}
//@TODO add logic for reading from several frames if required
int remaining = remaining();
if (remaining == 0) {
// if header was read, but payload is empty - read it
return read(b, offset, length);
}
if (length > remaining) {
length = remaining;
}
byteBuffer.get(b, offset, length);
frameBytesRead += length;
receivedMessageLength += length;
return length;
} else {
if (!byteBuffer.hasRemaining()) {
int eof = readFromChannel();
if (eof == -1) {
return -1;
}
}
int remaining = remaining();
if (length > remaining) {
length = remaining;
}
byteBuffer.get(b, offset, length);
return length;
}
}
public void forceHeaderRead() throws IOException {
readHeader();
}
private int readFrameHeaderIfRequired() {
if (!isDirectMode && !isLastFrame && !isReadingHeader && (frameBytesRead == 0 || frameBytesRead == currentFrameDataSize)) {
try {
readHeader();
} catch (IOException ex) {
return -1;
}
}
return 0;
}
private void readHeader() throws IOException {
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, MessagesMessages.WSTCP_1060_FRAMED_MESSAGE_IS_READ_HEADER_ENTER());
}
frameBytesRead = 0;
isReadingHeader = true;
// Read channel-id and message-id
int lowNeebleValue = DataInOutUtils.readInts4(this, headerTmpArray, 2, 0);
channelId = headerTmpArray[0];
messageId = headerTmpArray[1];
if (FrameType.isFrameContainsParams(messageId)) { //message types have description
// Read content-id and number-of-parameters
lowNeebleValue = DataInOutUtils.readInts4(this, headerTmpArray, 2, lowNeebleValue);
contentId = headerTmpArray[0];
final int paramNumber = headerTmpArray[1];
for(int i=0; i 0) {
if (byteBuffer.hasRemaining()) {
final int remainFrameBytes = currentFrameDataSize - frameBytesRead;
if (remainFrameBytes <= byteBuffer.remaining()) {
byteBuffer.position(byteBuffer.position() + remainFrameBytes);
return;
}
frameBytesRead += byteBuffer.remaining();
byteBuffer.position(byteBuffer.limit());
}
while(frameBytesRead < currentFrameDataSize) {
final int eof = readFromChannel();
if (eof == -1) {
String errorMessage = MessagesMessages.WSTCP_1062_FRAMED_MESSAGE_IS_READ_UNEXPECTED_EOF(isLastFrame, frameBytesRead, frameSize, currentFrameDataSize);
logger.log(Level.SEVERE, errorMessage);
throw new EOFException(errorMessage);
}
frameBytesRead += eof;
byteBuffer.position(byteBuffer.position() + eof);
}
// if extra frame bytes were read - move position backwards
byteBuffer.position(byteBuffer.position() - (frameBytesRead - currentFrameDataSize));
}
}
/**
* Read bytes using the read ReadSelector
*/
private int doRead(){
if ( socketChannel == null ) return -1;
if (isEOF()) {
return -1;
}
byteBuffer.clear();
int count;
int byteRead = 0;
Selector readSelector = null;
SelectionKey tmpKey = null;
try{
do {
count = socketChannel.read(byteBuffer);
byteRead += count;
} while (count > 0);
if (count == -1 && byteRead >= 0) byteRead++;
if ( byteRead == 0 ){
readSelector = SelectorFactory.getSelector();
if ( readSelector == null ){
return 0;
}
tmpKey = socketChannel
.register(readSelector,SelectionKey.OP_READ);
tmpKey.interestOps(tmpKey.interestOps() | SelectionKey.OP_READ);
final int code = readSelector.select(READ_TIMEOUT);
//Nothing so return.
tmpKey.interestOps(tmpKey.interestOps() & (~SelectionKey.OP_READ));
if ( code == 0 ){
return 0;
}
do {
count = socketChannel.read(byteBuffer);
byteRead += count;
} while (count > 0);
if (count == -1 && byteRead >= 0) byteRead++;
}
} catch (Exception e){
logger.log(Level.SEVERE, MessagesMessages.WSTCP_0018_ERROR_READING_FROM_SOCKET(), e);
return -1;
} finally {
if (tmpKey != null)
tmpKey.cancel();
if ( readSelector != null){
try{
readSelector.selectNow();
} catch (IOException ex){
}
SelectorFactory.returnSelector(readSelector);
}
byteBuffer.flip();
}
return byteRead;
}
public boolean isMessageInProcess() {
return currentFrameDataSize != 0 && !isEOF();
}
private boolean isEOF() {
return isLastFrame && frameBytesRead >= currentFrameDataSize;
}
private int remaining() {
if (isReadingHeader || isDirectMode) {
return byteBuffer.remaining();
}
return Math.min(currentFrameDataSize - frameBytesRead, byteBuffer.remaining());
}
@Override
public void reset() {
frameBytesRead = 0;
currentFrameDataSize = 0;
isLastFrame = false;
isReadingHeader = false;
contentId = -1;
messageId = -1;
contentProps.clear();
receivedMessageLength = 0;
}
@Override
public void activate() {
}
@Override
public void passivate() {
reset();
setSocketChannel(null);
setByteBuffer(null);
}
@Override
public String toString() {
return "ByteBuffer: " +
byteBuffer +
" FrameBytesRead: " +
frameBytesRead +
" CurrentFrameDataSize: " +
currentFrameDataSize +
" isLastFrame: " +
isLastFrame +
" isDirectMode: " +
isDirectMode +
" isReadingHeader: " +
isReadingHeader;
}
}