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

org.refcodes.connection.impls.AbstractReceiver Maven / Gradle / Ivy

Go to download

Artifact providing functionality for connection related issues such as receiving or transmitting data in a unified way.

There is a newer version: 1.0.0
Show newest version
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// =============================================================================
// This code is copyright (c) by Siegfried Steiner, Munich, Germany and licensed
// under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// =============================================================================
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// together with the GPL linking exception applied; as being applied by the GNU
// Classpath ("http://www.gnu.org/software/classpath/license.html")
// =============================================================================
// Apache License, v2.0 ("http://www.apache.org/licenses/LICENSE-2.0")
// =============================================================================
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.connection.impls;

import java.io.Serializable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import org.refcodes.component.impls.AbstractConnectableAutomaton;
import org.refcodes.component.traps.OpenException;
import org.refcodes.connection.Receiver;
import org.refcodes.controlflow.RetryCounter;
import org.refcodes.controlflow.impls.RetryCounterImpl;
import org.refcodes.data.consts.ControlFlowConsts;
import org.refcodes.logger.RuntimeLogger;
import org.refcodes.logger.factories.impls.RuntimeLoggerFactorySingleton;

/**
 * The {@link AbstractReceiver} is a base abstract implementation of the
 * {@link Receiver} interface providing common functionality for concrete real
 * live {@link Receiver} implementations.
 * 

* A blocking queue is used internally to which received datagrams are put via * {@link #pushDatagram(Serializable)} and which can be retrieved via * {@link #readDatagram()}. *

* Make sure your code fetches the datagrams quick enough to prevent filling up * of the queue. In case the queue is filled up, adding elements via * {@link #pushDatagram(Serializable)} to the queue is blocked until elements * are taken from the queue via {@link #readDatagram()}. * * @param The type of the datagram to be operated with. */ public abstract class AbstractReceiver extends AbstractConnectableAutomaton implements Receiver { private static RuntimeLogger LOGGER = RuntimeLoggerFactorySingleton.getInstance().createInstance(); // ///////////////////////////////////////////////////////////////////////// // CONSTANTS: // ///////////////////////////////////////////////////////////////////////// private static final int MAX_MESSAGE_QUEUE_SIZE = 1000; // ///////////////////////////////////////////////////////////////////////// // VARIABLES: // ///////////////////////////////////////////////////////////////////////// private LinkedBlockingQueue _datagramQueue; // ///////////////////////////////////////////////////////////////////////// // CONSTRUCTORS: // ///////////////////////////////////////////////////////////////////////// /** * Constructs a {@link AbstractReceiver} with a default sized blocking queue * enabling a maximum of {@link #MAX_MESSAGE_QUEUE_SIZE} datagrams. * ------------------------------------------------------------------------- * Make sure your code fetches the datagrams quick enough to prevent filling * up of the queue. In case the queue is filled up, adding elements via * {@link #pushDatagram(Serializable)} to the queue is blocked until * elements are taken from the queue via {@link #readDatagram()}. */ public AbstractReceiver() { _datagramQueue = new LinkedBlockingQueue( MAX_MESSAGE_QUEUE_SIZE ); } /** * Constructs a {@link AbstractReceiver} with a custom sized blocking queue * enabling a maximum of datagrams as specified by the capacity parameter. * ------------------------------------------------------------------------- * Make sure your code fetches the datagrams quick enough to prevent filling * up of the queue. In case the queue is filled up, adding elements via * {@link #pushDatagram(Serializable)} to the queue is blocked until * elements are taken from the queue via {@link #readDatagram()}. * * @param aCapacity The capacity of the queue holding the received * datagrams. */ public AbstractReceiver( int aCapacity ) { _datagramQueue = new LinkedBlockingQueue( aCapacity ); } // ///////////////////////////////////////////////////////////////////////// // METHODS: // ///////////////////////////////////////////////////////////////////////// /** * {@inheritDoc} */ @Override public DATA readDatagram() throws OpenException, InterruptedException { // Enable the caller to get all elements from the queue: if ( _datagramQueue.isEmpty() && !isOpened() ) { throw new OpenException( "Unable to read datagram as the connection is NOT OPEN; connection status is " + getConnectionStatus() + "." ); } return _datagramQueue.take(); } /** * {@inheritDoc} */ @Override public boolean hasDatagram() throws OpenException { // Enable the caller to get all elements from the queue: if ( _datagramQueue.isEmpty() && !isOpened() ) { throw new OpenException( "Unable to read datagram as the connection is NOT OPEN; connection status is " + getConnectionStatus() + "." ); } return !_datagramQueue.isEmpty(); } /** * {@inheritDoc} */ @Override public void close() { if ( isOpened() ) { super.close(); releaseAll(); } } /** * {@inheritDoc} */ @Override public void releaseAll() { synchronized ( _datagramQueue ) { _datagramQueue.notifyAll(); } } // ///////////////////////////////////////////////////////////////////////// // HOOKS: // ///////////////////////////////////////////////////////////////////////// /** * Pushes a datagram into the receiver and puts it into the blocking queue * containing the so far received datagrams. Them datagrams can be retrieved * via {@link #readDatagram()}: use {@link #hasDatagram()} to test * beforehand whether there is a datagram available. * * @param aDatagram The datagram to be pushed at the end of the blocking * queue; to be retrieved with the {@link #readDatagram()} method. */ protected void pushDatagram( DATA aDatagram ) throws OpenException { if ( !isOpened() ) { throw new OpenException( "Unable to push datagram <" + aDatagram.getClass().getName() + "> as the connection is NOT OPEN; connection status is " + getConnectionStatus() + "." ); } RetryCounter theRetryCounter = new RetryCounterImpl( ControlFlowConsts.MAX_IO_RETRIES ); try { while ( !_datagramQueue.offer( aDatagram, ControlFlowConsts.MAX_CODE_LOOP_SLEEP_TIME_IN_MS, TimeUnit.MILLISECONDS ) && theRetryCounter.nextRetry() ) { LOGGER.warn( "Trying to offer (add) a datagram to the datagram queue, though the queue is full, this is retry # <" + theRetryCounter.getRetryCount() + ">, aborting after <" + theRetryCounter.getRetryNumber() + "> retries. Retrying now after a delay of <" + (ControlFlowConsts.MAX_CODE_LOOP_SLEEP_TIME_IN_MS / 1000) + "> seconds..." ); if ( !theRetryCounter.hasNextRetry() ) { throw new OpenException( "Unable to process the datagram after <" + theRetryCounter.getRetryNumber() + "> retries, aborting retries, dismissing datagram \"" + aDatagram.toString() + "\"!", null, null ); } } } catch ( InterruptedException e ) { /* ignore */} } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy