All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xsocket.connection.BlockingConnection Maven / Gradle / Ivy

/*
 * Copyright (c) xlightweb.org, 2006 - 2010. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
 * The latest copy of this software may be found on http://www.xsocket.org/
 */
package org.xsocket.connection;

import java.io.IOException;



import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLContext;

import org.xsocket.DataConverter;
import org.xsocket.MaxReadSizeExceededException;




/**
 * Implementation of the IBlockingConnection interface. Internally a {@link INonBlockingConnection}
 * will be used. A BlockingConnection wraps a INonBlockingConnection. There are two ways to 
 * create a BlockingConnection: 
 * 
    *
  • by passing over the remote address (e.g. host name & port), or
  • *
  • by passing over a INonBlockingConnection, which will be wrapped
  • *
*

* * A newly created connection is in the open state. Write or read methods can be called immediately

* * The methods of this class are not thread-safe. * * @author [email protected] */ public class BlockingConnection implements IBlockingConnection { private static final Logger LOG = Logger.getLogger(BlockingConnection.class.getName()); public static final String READ_TIMEOUT_KEY = "org.xsocket.connection.readtimeoutMillis"; public static final int DEFAULT_TIMEOUT = Integer.parseInt(System.getProperty(READ_TIMEOUT_KEY, Integer.toString(DEFAULT_READ_TIMEOUT))); private final ReadNotificationHandler handler = new ReadNotificationHandler(); private final Object readGuard = new Object(); private final INonBlockingConnection delegate; private int readTimeout = DEFAULT_TIMEOUT; private AtomicBoolean disconnected = new AtomicBoolean(false); private AtomicBoolean idleTimeout = new AtomicBoolean(false); private AtomicBoolean connectionTimeout = new AtomicBoolean(false); private AtomicBoolean isClosed = new AtomicBoolean(false); /** * constructor.

* * @param hostname the remote host * @param port the port of the remote host to connect * @throws IOException If some other I/O error occurs */ public BlockingConnection(String hostname, int port) throws IOException { this(new InetSocketAddress(hostname, port), null, true, Integer.MAX_VALUE, new HashMap(), null, false); } /** * constructor.

* * @param hostname the remote host * @param port the port of the remote host to connect * @param options the socket options * @throws IOException If some other I/O error occurs */ public BlockingConnection(String hostname, int port, Map options) throws IOException { this(new InetSocketAddress(hostname, port), null, true, Integer.MAX_VALUE, options, null, false); } /** * constructor * * @param address the remote host address * @param port the remote host port * @throws IOException If some other I/O error occurs */ public BlockingConnection(InetAddress address, int port) throws IOException { this(address, port, Integer.MAX_VALUE, new HashMap(), null, false); } /** * constructor * * @param address the remote host address * @param port the remote host port * @param connectTimeoutMillis the timeout of the connect procedure * @throws IOException If some other I/O error occurs */ public BlockingConnection(InetAddress address, int port, int connectTimeoutMillis) throws IOException{ this(new InetSocketAddress(address, port), null, true, connectTimeoutMillis, new HashMap(), null, false); } /** * constructor * * @param address the remote host name * @param port the remote host port * @param sslContext the sslContext to use * @param sslOn true, activate SSL mode. false, ssl can be activated by user (see {@link IReadWriteableConnection#activateSecuredMode()}) * @throws IOException If some other I/O error occurs */ public BlockingConnection(InetAddress address, int port, SSLContext sslContext, boolean sslOn) throws IOException { this(new InetSocketAddress(address, port), null, true, Integer.MAX_VALUE, new HashMap(), sslContext, sslOn); } /** * constructor * * @param address the remote host name * @param port the remote host port * @param connectTimeoutMillis the timeout of the connect procedure * @param sslContext the sslContext to use * @param sslOn true, activate SSL mode. false, ssl can be activated by user (see {@link IReadWriteableConnection#activateSecuredMode()}) * @throws IOException If some other I/O error occurs */ public BlockingConnection(InetAddress address, int port, int connectTimeoutMillis, SSLContext sslContext, boolean sslOn) throws IOException { this(new InetSocketAddress(address, port), null, true, connectTimeoutMillis, new HashMap(), sslContext, sslOn); } /** * constructor * * @param address the remote host name * @param port the remote host port * @param options the socket options * @param sslContext the sslContext to use * @param sslOn true, activate SSL mode. false, ssl can be activated by user (see {@link IReadWriteableConnection#activateSecuredMode()}) * @throws IOException If some other I/O error occurs */ public BlockingConnection(InetAddress address, int port, Map options, SSLContext sslContext, boolean sslOn) throws IOException { this(new InetSocketAddress(address, port), null, true, Integer.MAX_VALUE, options, sslContext, sslOn); } /** * constructor * * @param address the remote host name * @param port the remote host port * @param connectTimeoutMillis the timeout of the connect procedure * @param options the socket options * @param sslContext the sslContext to use * @param sslOn true, activate SSL mode. false, ssl can be activated by user (see {@link IReadWriteableConnection#activateSecuredMode()}) * @throws IOException If some other I/O error occurs */ public BlockingConnection(InetAddress address, int port, int connectTimeoutMillis, Map options, SSLContext sslContext, boolean sslOn) throws IOException { this(new InetSocketAddress(address, port), null, true, connectTimeoutMillis, options, sslContext, sslOn); } /** * constructor * * @param hostname the remote host name * @param port the remote host port * @param sslContext the sslContext to use or * @param sslOn true, activate SSL mode. false, ssl can be activated by user (see {@link IReadWriteableConnection#activateSecuredMode()}) * @throws IOException If some other I/O error occurs */ public BlockingConnection(String hostname, int port, SSLContext sslContext, boolean sslOn) throws IOException { this(new InetSocketAddress(hostname, port), null, true, Integer.MAX_VALUE, new HashMap(), sslContext, sslOn); } /** * constructor * * @param remoteAddress the remote address * @param localAddress the local address * @param waitForConnect true, if the constructor should block until the connection is established. * @param connectTimeoutMillis the connection timeout * @param options the socket options * @param sslContext the ssl context or * @param sslOn true, if ssl mode * @throws IOException If some other I/O error occurs */ public BlockingConnection(InetSocketAddress remoteAddress, InetSocketAddress localAddress, boolean waitForConnect, int connectTimeoutMillis, Map options, SSLContext sslContext, boolean sslOn) throws IOException { this.delegate= new NonBlockingConnection(remoteAddress, localAddress, handler, waitForConnect, connectTimeoutMillis, options, sslContext, sslOn); } /** * Constructor.

* * By creating a BlokingConnection based on the given NonBlockingConnection the * assigned handler of the NonBlockingConnection will be removed (if exists). Take * care by using this on the server-side (see tutorial for more informations). * * @param delegate the underlying non blocking connection * @throws IOException If some other I/O error occurs */ public BlockingConnection(INonBlockingConnection delegate) throws IOException { this.delegate = delegate; delegate.setHandler(handler); } final INonBlockingConnection getDelegate() { return delegate; } /** * {@inheritDoc} */ public void setReadTimeoutMillis(int timeout) throws IOException { this.readTimeout = timeout; int soTimeout = (Integer) delegate.getOption(SO_TIMEOUT); if (timeout > soTimeout) { delegate.setOption(SO_TIMEOUT, timeout); } } /** * {@inheritDoc} */ public void setReceiveTimeoutMillis(int timeout) throws IOException { setReadTimeoutMillis(timeout); } /** * {@inheritDoc} */ public final int getReceiveTimeoutMillis() throws IOException { return getReadTimeoutMillis(); } /** * {@inheritDoc} */ public int getReadTimeoutMillis() throws IOException { return readTimeout; } /** * {@inheritDoc} */ public int getMaxReadBufferThreshold() { return delegate.getMaxReadBufferThreshold(); } /** * {@inheritDoc} */ public void setMaxReadBufferThreshold(int size) { delegate.setMaxReadBufferThreshold(size); } /** * {@inheritDoc} */ public final void setEncoding(String defaultEncoding) { delegate.setEncoding(defaultEncoding); } /** * {@inheritDoc} */ public final String getEncoding() { return delegate.getEncoding(); } /** * return if the data source is open. Default is true * @return true, if the data source is open */ public final boolean isOpen() { return !isClosed.get() && delegate.isOpen(); } /** * {@inheritDoc} */ public boolean isServerSide() { return delegate.isServerSide(); } /** * {@inheritDoc} */ public final void close() throws IOException { isClosed.set(true); delegate.close(); } /** * {@inheritDoc} */ public final void flush() throws ClosedChannelException, IOException, SocketTimeoutException { delegate.flush(); } /** * {@inheritDoc} */ public String getId() { return delegate.getId(); } /** * {@inheritDoc} */ public final InetAddress getRemoteAddress() { return delegate.getRemoteAddress(); } /** * {@inheritDoc} */ public final int getRemotePort() { return delegate.getRemotePort(); } /** * {@inheritDoc} */ public final InetAddress getLocalAddress() { return delegate.getLocalAddress(); } /** * {@inheritDoc} */ public final int getLocalPort() { return delegate.getLocalPort(); } /** * {@inheritDoc} */ public final int getPendingWriteDataSize() { return delegate.getPendingWriteDataSize(); } /** * {@inheritDoc} */ public final void suspendRead() throws IOException { delegate.suspendReceiving(); } /** * {@inheritDoc} */ public boolean isReadSuspended() { return delegate.isReceivingSuspended(); } /** * {@inheritDoc} */ public final void resumeRead() throws IOException { delegate.resumeReceiving(); } /** * {@inheritDoc} */ public boolean isReceivingSuspended() { return delegate.isReceivingSuspended(); } /** * {@inheritDoc} */ public void resumeReceiving() throws IOException { delegate.resumeReceiving(); } /** * {@inheritDoc} */ public void suspendReceiving() throws IOException { delegate.suspendReceiving(); } /** * {@inheritDoc} */ public void setFlushmode(FlushMode flushMode) { delegate.setFlushmode(flushMode); } /** * {@inheritDoc} */ public FlushMode getFlushmode() { return delegate.getFlushmode(); } /** * {@inheritDoc} */ public final void setOption(String name, Object value) throws IOException { delegate.setOption(name, value); } /** * {@inheritDoc} */ public final Object getOption(String name) throws IOException { return delegate.getOption(name); } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") public final Map getOptions() { return delegate.getOptions(); } /** * {@inheritDoc} */ public final void setIdleTimeoutMillis(long timeoutInMillis) { delegate.setIdleTimeoutMillis(timeoutInMillis); } /** * {@inheritDoc} */ public final long getIdleTimeoutMillis() { return delegate.getIdleTimeoutMillis(); } /** * {@inheritDoc} */ public final void setConnectionTimeoutMillis(long timeoutMillis) { delegate.setConnectionTimeoutMillis(timeoutMillis); } /** * {@inheritDoc} */ public final long getConnectionTimeoutMillis() { return delegate.getConnectionTimeoutMillis(); } /** * {@inheritDoc} */ public long getRemainingMillisToConnectionTimeout() { return delegate.getRemainingMillisToConnectionTimeout(); } /** * {@inheritDoc} */ public long getRemainingMillisToIdleTimeout() { return delegate.getRemainingMillisToIdleTimeout(); } /** * {@inheritDoc} */ public final void setAttachment(Object obj) { delegate.setAttachment(obj); } /** * {@inheritDoc} */ public final Object getAttachment() { return delegate.getAttachment(); } /** * {@inheritDoc} */ public final void setAutoflush(boolean autoflush) { delegate.setAutoflush(autoflush); } /** * {@inheritDoc} */ public final boolean isAutoflush() { return delegate.isAutoflush(); } /** * {@inheritDoc} */ public final void activateSecuredMode() throws IOException { delegate.activateSecuredMode(); } /** * {@inheritDoc} */ public void deactivateSecuredMode() throws IOException { delegate.deactivateSecuredMode(); } /** * {@inheritDoc} */ public boolean isSecure() { return delegate.isSecure(); } /** * {@inheritDoc} */ public final void markReadPosition() { delegate.markReadPosition(); } /** * {@inheritDoc} */ public final void markWritePosition() { delegate.markWritePosition(); } /** * {@inheritDoc}. */ public void unread(ByteBuffer[] buffers) throws IOException { delegate.unread(buffers); } /** * {@inheritDoc}. */ public void unread(byte[] bytes) throws IOException { delegate.unread(bytes); } /** * {@inheritDoc}. */ public void unread(ByteBuffer buffer) throws IOException { delegate.unread(buffer); } /** * {@inheritDoc}. */ public void unread(String text) throws IOException { delegate.unread(text); } /** * {@inheritDoc}. */ public final int read(ByteBuffer buffer) throws IOException, ClosedChannelException { int size = buffer.remaining(); if (size < 1) { return 0; } return new ByteBufferReadTask(buffer).read(); } private final class ByteBufferReadTask extends ReadTask { private final ByteBuffer buffer; public ByteBufferReadTask(ByteBuffer buffer) { this.buffer = buffer; } @Override Integer doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { try { available(1); // ensure that at minimum the required length is available return delegate.read(buffer); } catch (ClosedChannelException cce) { if (!isClosed.getAndSet(true)) { return -1; } else { throw cce; } } } } private Integer getSize() { try { return delegate.available(); } catch (IOException ioe) { return null; } } /** * {@inheritDoc} */ public final byte readByte() throws IOException, SocketTimeoutException { return new ByteReadTask().read(); } private final class ByteReadTask extends ReadTask { @Override Byte doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { return delegate.readByte(); } } /** * {@inheritDoc} */ public final short readShort() throws IOException, SocketTimeoutException { return new ShortReadTask().read(); } private final class ShortReadTask extends ReadTask { @Override Short doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { return delegate.readShort(); } } /** * {@inheritDoc} */ public final int readInt() throws IOException, SocketTimeoutException { return new IntegerReadTask().read(); } private final class IntegerReadTask extends ReadTask { @Override Integer doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { return delegate.readInt(); } } /** * {@inheritDoc} */ public final long readLong() throws IOException, SocketTimeoutException { return new LongReadTask().read(); } private final class LongReadTask extends ReadTask { @Override Long doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { return delegate.readLong(); } } /** * {@inheritDoc} */ public final double readDouble() throws IOException, SocketTimeoutException { return new DoubleReadTask().read(); } private final class DoubleReadTask extends ReadTask { @Override Double doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { return delegate.readDouble(); } } /** * {@inheritDoc} */ public final ByteBuffer[] readByteBufferByDelimiter(String delimiter) throws IOException, SocketTimeoutException { return readByteBufferByDelimiter(delimiter, getEncoding()); } /** * {@inheritDoc} */ public final ByteBuffer[] readByteBufferByDelimiter(String delimiter, int maxLength) throws IOException, MaxReadSizeExceededException, SocketTimeoutException { return readByteBufferByDelimiter(delimiter, getEncoding(), maxLength); } /** * {@inheritDoc} */ public final ByteBuffer[] readByteBufferByDelimiter(String delimiter, String encoding) throws IOException, SocketTimeoutException { return readByteBufferByDelimiter(delimiter, encoding, Integer.MAX_VALUE); } /** * {@inheritDoc} */ public final ByteBuffer[] readByteBufferByDelimiter(String delimiter, String encoding, int maxLength) throws IOException, MaxReadSizeExceededException, SocketTimeoutException { return new ByteBuffersByDelimiterReadTask(delimiter, encoding, maxLength).read(); } private final class ByteBuffersByDelimiterReadTask extends ReadTask { private final String delimiter; private final String encoding; private final int maxLength; public ByteBuffersByDelimiterReadTask(String delimiter, String encoding, final int maxLength) { this.delimiter = delimiter; this.encoding = encoding; this.maxLength = maxLength; } @Override ByteBuffer[] doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { return delegate.readByteBufferByDelimiter(delimiter, encoding, maxLength); } } /** * {@inheritDoc} */ public final ByteBuffer[] readByteBufferByLength(int length) throws IOException, SocketTimeoutException { if (length <= 0) { return new ByteBuffer[0]; } return new ByteBuffersByLengthReadTask(length).read(); } private final class ByteBuffersByLengthReadTask extends ReadTask { private final int length; public ByteBuffersByLengthReadTask(int length) { this.length = length; } @Override ByteBuffer[] doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { return delegate.readByteBufferByLength(length); } } /** * {@inheritDoc} */ public final byte[] readBytesByDelimiter(String delimiter) throws IOException, SocketTimeoutException { return readBytesByDelimiter(delimiter, getEncoding()); } /** * {@inheritDoc} */ public final byte[] readBytesByDelimiter(String delimiter, int maxLength) throws IOException, MaxReadSizeExceededException, SocketTimeoutException { return readBytesByDelimiter(delimiter, getEncoding(), maxLength); } /** * {@inheritDoc} */ public final byte[] readBytesByDelimiter(String delimiter, String encoding) throws IOException, SocketTimeoutException { return readBytesByDelimiter(delimiter, encoding, Integer.MAX_VALUE); } /** * {@inheritDoc} */ public final byte[] readBytesByDelimiter(String delimiter, String encoding, int maxLength) throws IOException, MaxReadSizeExceededException, SocketTimeoutException { return DataConverter.toBytes(readByteBufferByDelimiter(delimiter, encoding, maxLength)); } /** * {@inheritDoc} */ public final byte[] readBytesByLength(int length) throws IOException, SocketTimeoutException { return DataConverter.toBytes(readByteBufferByLength(length)); } /** * {@inheritDoc} */ public final String readStringByDelimiter(String delimiter) throws IOException, UnsupportedEncodingException, SocketTimeoutException { return readStringByDelimiter(delimiter, Integer.MAX_VALUE); } /** * {@inheritDoc} */ public final String readStringByDelimiter(String delimiter, int maxLength) throws IOException, UnsupportedEncodingException, MaxReadSizeExceededException, SocketTimeoutException { return readStringByDelimiter(delimiter, getEncoding(), maxLength); } /** * {@inheritDoc} */ public final String readStringByDelimiter(String delimiter, String encoding) throws IOException, UnsupportedEncodingException, MaxReadSizeExceededException, SocketTimeoutException { return readStringByDelimiter(delimiter, encoding, Integer.MAX_VALUE); } /** * {@inheritDoc} */ public final String readStringByDelimiter(String delimiter, String encoding, int maxLength) throws IOException, UnsupportedEncodingException, MaxReadSizeExceededException, SocketTimeoutException { return DataConverter.toString(readByteBufferByDelimiter(delimiter, encoding, maxLength), encoding); } /** * {@inheritDoc} */ public final String readStringByLength(int length) throws IOException, UnsupportedEncodingException, SocketTimeoutException { return readStringByLength(length, getEncoding()); } /** * {@inheritDoc} */ public final String readStringByLength(int length, String encoding) throws IOException, UnsupportedEncodingException, SocketTimeoutException { return DataConverter.toString(readByteBufferByLength(length), encoding); } /** * {@inheritDoc} */ public final long transferTo(WritableByteChannel target, int length) throws IOException, SocketTimeoutException { long written = 0; ByteBuffer[] buffers = readByteBufferByLength(length); for (ByteBuffer buffer : buffers) { written += target.write(buffer); } return written; } /** * {@inheritDoc} */ public final boolean resetToWriteMark() { return delegate.resetToWriteMark(); } /** * {@inheritDoc} */ public final boolean resetToReadMark() { return delegate.resetToReadMark(); } /** * {@inheritDoc} */ public final void removeReadMark() { delegate.removeReadMark(); } /** * {@inheritDoc} */ public final void removeWriteMark() { delegate.removeWriteMark(); } /** * {@inheritDoc} */ public final int write(byte b) throws IOException, BufferOverflowException { return delegate.write(b); } /** * {@inheritDoc} */ public final int write(byte... bytes) throws IOException { return delegate.write(bytes); } /** * {@inheritDoc} */ public void write(byte[] bytes, IWriteCompletionHandler writeCompletionHandler) throws IOException { delegate.write(bytes, writeCompletionHandler); } /** * {@inheritDoc} */ public final int write(byte[] bytes, int offset, int length) throws IOException { return delegate.write(bytes, offset, length); } /** * {@inheritDoc} */ public void write(byte[] bytes, int offset, int length, IWriteCompletionHandler writeCompletionHandler) throws IOException { delegate.write(bytes, offset, length, writeCompletionHandler); } /** * {@inheritDoc} */ public final int write(short s) throws IOException { return delegate.write(s); } /** * {@inheritDoc} */ public final int write(int i) throws IOException { return delegate.write(i); } /** * {@inheritDoc} */ public final int write(long l) throws IOException { return delegate.write(l); } /** * {@inheritDoc} */ public final int write(double d) throws IOException { return delegate.write(d); } /** * {@inheritDoc} */ public final int write(String message) throws IOException { return delegate.write(message); } /** * {@inheritDoc} */ public final int write(String message, String encoding) throws IOException { return delegate.write(message, encoding); } /** * {@inheritDoc} */ public void write(String message, String encoding, IWriteCompletionHandler writeCompletionHandler) throws IOException { delegate.write(message, encoding, writeCompletionHandler); } /** * {@inheritDoc} */ public final long write(ArrayList buffers) throws IOException { return delegate.write(buffers); } /** * {@inheritDoc} */ public final long write(List buffers) throws IOException { return delegate.write(buffers); } /** * {@inheritDoc} */ public final long write(ByteBuffer[] buffers) throws IOException { return delegate.write(buffers); } /** * {@inheritDoc} */ public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { return delegate.write(srcs, offset, length); } /** * {@inheritDoc} */ public final int write(ByteBuffer buffer) throws IOException { return delegate.write(buffer); } /** * {@inheritDoc} */ public void write(ByteBuffer buffer, IWriteCompletionHandler writeCompletionHandler) throws IOException { delegate.write(buffer, writeCompletionHandler); } /** * {@inheritDoc} */ public void write(ByteBuffer[] buffers, IWriteCompletionHandler writeCompletionHandler) throws IOException { delegate.write(buffers, writeCompletionHandler); } /** * {@inheritDoc} */ public void write(ByteBuffer[] srcs, int offset, int length, IWriteCompletionHandler writeCompletionHandler) throws IOException { delegate.write(srcs, offset,length, writeCompletionHandler); } /** * {@inheritDoc} */ public final long transferFrom(ReadableByteChannel source) throws IOException { return delegate.transferFrom(source); } /** * {@inheritDoc} */ public void write(List buffers, IWriteCompletionHandler writeCompletionHandler) throws IOException { delegate.write(buffers, writeCompletionHandler); } /** * {@inheritDoc} */ public final long transferFrom(ReadableByteChannel source, int chunkSize) throws IOException { return delegate.transferFrom(source, chunkSize); } public long transferFrom(FileChannel source) throws IOException { return delegate.transferFrom(source); } @Override public String toString() { return delegate.toString(); } private void onReadDataInserted() { synchronized (readGuard) { readGuard.notifyAll(); } } final class ReadNotificationHandler implements IDataHandler, IDisconnectHandler, IConnectionTimeoutHandler, IIdleTimeoutHandler, IUnsynchronized { public boolean onData(INonBlockingConnection connection) throws IOException, BufferUnderflowException, MaxReadSizeExceededException { onReadDataInserted(); return true; } public boolean onDisconnect(INonBlockingConnection connection) throws IOException { disconnected.set(true); onReadDataInserted(); return true; } public boolean onConnectionTimeout(INonBlockingConnection connection) throws IOException { connectionTimeout.set(true); onReadDataInserted(); connection.close(); return true; } public boolean onIdleTimeout(INonBlockingConnection connection) throws IOException { idleTimeout.set(true); onReadDataInserted(); connection.close(); return true; } } private abstract class ReadTask { final T read() throws IOException, SocketTimeoutException, MaxReadSizeExceededException { long start = System.currentTimeMillis(); long remainingTime = readTimeout; do { int revision = delegate.getReadBufferVersion(); try { try { return doRead(); } catch (RevisionAwareBufferUnderflowException rbe) { synchronized (readGuard) { if (rbe.getRevision() != delegate.getReadBufferVersion()) { continue; } else { throw new BufferUnderflowException(); // "jump" into catch (BufferUnderflowException) } } } } catch (BufferUnderflowException bue) { synchronized (readGuard) { // no notification event is occurred meanwhile if (revision == delegate.getReadBufferVersion()) { // no more data expected? (connection is destroyed) if (disconnected.get()) { throw new ExtendedClosedChannelException("channel " + getId() + " is closed (read buffer size=" + getSize() + ")"); } else { if (LOG.isLoggable(Level.FINE)) { LOG.fine("waiting for more reveived data (guard: " + readGuard + ")"); } try { readGuard.wait(remainingTime); } catch (InterruptedException ie) { // Restore the interrupted status Thread.currentThread().interrupt(); } } } } } long elpased = System.currentTimeMillis() - start; remainingTime -= elpased; } while (remainingTime > 0); if (LOG.isLoggable(Level.FINE)) { LOG.fine("receive timeout " + readTimeout + " sec reached. throwing timeout exception"); } throw new SocketTimeoutException("timeout " + readTimeout + " millis reached"); } protected final int available(int required) throws IOException, BufferUnderflowException, ClosedChannelException { synchronized (readGuard) { int available = delegate.available(); if (available == -1) { throw new ClosedChannelException(); } else if (available < required) { throw new RevisionAwareBufferUnderflowException(delegate.getReadBufferVersion()); } else { return available; } } } abstract T doRead() throws IOException, SocketTimeoutException, MaxReadSizeExceededException; } private static final class RevisionAwareBufferUnderflowException extends BufferUnderflowException { private static final long serialVersionUID = -5623771436953505286L; private final int revision; public RevisionAwareBufferUnderflowException(int revision) { this.revision = revision; } public int getRevision() { return revision; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy