
org.refcodes.io.ext.observer.ObservableConnectionRequestReceiver Maven / Gradle / Ivy
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// =============================================================================
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed 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/TEXT-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.io.ext.observer;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.refcodes.component.Component;
import org.refcodes.component.ConnectionStatus;
import org.refcodes.component.ext.observer.CloseEvent;
import org.refcodes.component.ext.observer.ClosedEvent;
import org.refcodes.component.ext.observer.ConnectionEvent;
import org.refcodes.component.ext.observer.ConnectionObserver.ConnectionRequestObserver;
import org.refcodes.component.ext.observer.ConnectionStatusEvent;
import org.refcodes.component.ext.observer.OpenEvent;
import org.refcodes.component.ext.observer.OpenedEvent;
import org.refcodes.controlflow.ExecutionStrategy;
import org.refcodes.exception.VetoException;
import org.refcodes.exception.VetoException.VetoRuntimeException;
import org.refcodes.io.ConnectionDatagramsReceiver;
import org.refcodes.observer.AbstractObservable;
import org.refcodes.observer.ActionEvent;
import org.refcodes.observer.EventMetaData;
import org.refcodes.observer.Observable;
/**
* The {@link ObservableConnectionRequestReceiver} extends the
* {@link ConnectionDatagramsReceiver} with {@link ConnectionRequestObserver}
* functionality.
*
* @param The type of the datagram to be operated with.
* @param The type of the connection to be used.
*/
public class ObservableConnectionRequestReceiver implements ConnectionDatagramsReceiver, Observable>, Component {
// /////////////////////////////////////////////////////////////////////////
// STATICS:
// /////////////////////////////////////////////////////////////////////////
private static final Logger LOGGER = Logger.getLogger( ObservableConnectionReceiver.class.getName() );
// /////////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////////
private ConnectionDatagramsReceiver _connectionReceiver;
private EventMetaData _eventMetaData;
private boolean _isDestroyed = false;
private ConnectionObservable _observable;
private CON _source;
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Constructs a {@link ObservableConnectionRequestReceiver} with the given
* attributes.
*
* @param aConnectionReceiver The {@link ConnectionDatagramsReceiver} to
* which the connection method calls are to be delegated to.
*/
public ObservableConnectionRequestReceiver( ConnectionDatagramsReceiver aConnectionReceiver ) {
_connectionReceiver = aConnectionReceiver;
_eventMetaData = new EventMetaData( this.getClass() );
_source = toSource();
_observable = new ConnectionObservable();
}
/**
* Constructs a {@link ObservableConnectionRequestReceiver} with the given
* attributes.
*
* @param aConnectionReceiver The {@link ConnectionDatagramsReceiver} to
* which the connection method calls are to be delegated to.
* @param aEventMetaData The {@link EventMetaData} to be used when firing
* events in case the {@link EventMetaData} is to be different from
* the auto-generated {@link EventMetaData}.
*/
public ObservableConnectionRequestReceiver( ConnectionDatagramsReceiver aConnectionReceiver, EventMetaData aEventMetaData ) {
_connectionReceiver = aConnectionReceiver;
_eventMetaData = aEventMetaData;
_source = toSource();
_observable = new ConnectionObservable();
}
/**
* Constructs a {@link ObservableConnectionRequestReceiver} with the given
* attributes.
*
* @param aConnectionReceiver The {@link ConnectionDatagramsReceiver} to
* which the connection method calls are to be delegated to.
* @param aEventMetaData The {@link EventMetaData} to be used when firing
* events in case the {@link EventMetaData} is to be different from
* the auto-generated {@link EventMetaData}.
* @param aExecutorService The executor service to be used when firing
* {@link ActionEvent} instances in multiple threads (if null then a
* default one is used).
* @param aExecutionStrategy The {@link ExecutionStrategy} to be used when
* firing {@link ActionEvent} instance (if null then the default
* {@link ExecutionStrategy#SEQUENTIAL} is used).
*/
public ObservableConnectionRequestReceiver( ConnectionDatagramsReceiver aConnectionReceiver, EventMetaData aEventMetaData, ExecutorService aExecutorService, ExecutionStrategy aExecutionStrategy ) {
_connectionReceiver = aConnectionReceiver;
_eventMetaData = aEventMetaData;
_source = toSource();
_observable = new ConnectionObservable( aExecutorService, aExecutionStrategy );
}
/**
* Constructs a {@link ObservableConnectionRequestReceiver} with the given
* attributes.
*
* @param aConnectionReceiver The {@link ConnectionDatagramsReceiver} to
* which the connection method calls are to be delegated to.
* @param aEventMetaData The {@link EventMetaData} to be used when firing
* events in case the {@link EventMetaData} is to be different from
* the auto-generated {@link EventMetaData}.
* @param aSource The source instance to be used when firing events in case
* the source is to be different from this class' instance.
*/
public ObservableConnectionRequestReceiver( ConnectionDatagramsReceiver aConnectionReceiver, EventMetaData aEventMetaData, Object aSource ) {
_connectionReceiver = aConnectionReceiver;
_eventMetaData = aEventMetaData;
_source = toSource();
_observable = new ConnectionObservable();
}
/**
* Constructs a {@link ObservableConnectionRequestReceiver} with the given
* attributes.
*
* @param aConnectionReceiver The {@link ConnectionDatagramsReceiver} to
* which the connection method calls are to be delegated to.
* @param aEventMetaData The {@link EventMetaData} to be used when firing
* events in case the {@link EventMetaData} is to be different from
* the auto-generated {@link EventMetaData}.
* @param aSource The source instance to be used when firing events in case
* the source is to be different from this class' instance.
* @param aExecutorService The executor service to be used when firing
* {@link ActionEvent} instances in multiple threads (if null then a
* default one is used).
* @param aExecutionStrategy The {@link ExecutionStrategy} to be used when
* firing {@link ActionEvent} instance (if null then the default
* {@link ExecutionStrategy#SEQUENTIAL} is used).
*/
public ObservableConnectionRequestReceiver( ConnectionDatagramsReceiver aConnectionReceiver, EventMetaData aEventMetaData, Object aSource, ExecutorService aExecutorService, ExecutionStrategy aExecutionStrategy ) {
_connectionReceiver = aConnectionReceiver;
_eventMetaData = aEventMetaData;
_source = toSource();
_observable = new ConnectionObservable( aExecutorService, aExecutionStrategy );
}
/**
* Constructs a {@link ObservableConnectionRequestReceiver} with the given
* attributes.
*
* @param aConnectionReceiver The {@link ConnectionDatagramsReceiver} to
* which the connection method calls are to be delegated to.
* @param aExecutorService The executor service to be used when firing
* {@link ActionEvent} instances in multiple threads (if null then a
* default one is used).
* @param aExecutionStrategy The {@link ExecutionStrategy} to be used when
* firing {@link ActionEvent} instance (if null then the default
* {@link ExecutionStrategy#SEQUENTIAL} is used).
*/
public ObservableConnectionRequestReceiver( ConnectionDatagramsReceiver aConnectionReceiver, ExecutorService aExecutorService, ExecutionStrategy aExecutionStrategy ) {
_connectionReceiver = aConnectionReceiver;
_eventMetaData = new EventMetaData( this.getClass() );
_source = toSource();
_observable = new ConnectionObservable( aExecutorService, aExecutionStrategy );
}
/**
* Constructs a {@link ObservableConnectionRequestReceiver} with the given
* attributes.
*
* @param aConnectionReceiver The {@link ConnectionDatagramsReceiver} to
* which the connection method calls are to be delegated to.
* @param aSource The source instance to be used when firing events in case
* the source is to be different from this class' instance.
*/
public ObservableConnectionRequestReceiver( ConnectionDatagramsReceiver aConnectionReceiver, Object aSource ) {
_connectionReceiver = aConnectionReceiver;
_eventMetaData = new EventMetaData( this.getClass() );
_source = toSource();
_observable = new ConnectionObservable();
}
/**
* Constructs a {@link ObservableConnectionRequestReceiver} with the given
* attributes.
*
* @param aConnectionReceiver The {@link ConnectionDatagramsReceiver} to
* which the connection method calls are to be delegated to.
* @param aSource The source instance to be used when firing events in case
* the source is to be different from this class' instance.
* @param aExecutorService The executor service to be used when firing
* {@link ActionEvent} instances in multiple threads (if null then a
* default one is used).
* @param aExecutionStrategy The {@link ExecutionStrategy} to be used when
* firing {@link ActionEvent} instance (if null then the default
* {@link ExecutionStrategy#SEQUENTIAL} is used).
*/
public ObservableConnectionRequestReceiver( ConnectionDatagramsReceiver aConnectionReceiver, Object aSource, ExecutorService aExecutorService, ExecutionStrategy aExecutionStrategy ) {
_connectionReceiver = aConnectionReceiver;
_eventMetaData = new EventMetaData( this.getClass() );
_source = toSource();
_observable = new ConnectionObservable( aExecutorService, aExecutionStrategy );
}
// /////////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
public int available() throws IOException {
return _connectionReceiver.available();
}
/**
* {@inheritDoc}
*/
@Override
public void close() throws IOException {
try {
_observable.fireEvent( new CloseEvent<>( _eventMetaData, _source ) );
}
catch ( VetoException aException ) {
throw new VetoRuntimeException( aException );
}
_connectionReceiver.close();
try {
_observable.fireEvent( new ClosedEvent( _eventMetaData, _source ) );
}
catch ( VetoException ignore ) {
/* Cannot happen here */
}
}
/**
* {@inheritDoc}
*/
@Override
public void destroy() {
if ( !_isDestroyed ) {
_isDestroyed = true;
try {
close();
}
catch ( IOException e ) {
LOGGER.log( Level.WARNING, "Unable to close malfunctioning connection.", e );
}
_connectionReceiver = null;
_observable.clear();
_observable = null;
_source = null;
_eventMetaData = null;
}
}
/**
* {@inheritDoc}
*/
@Override
public ConnectionStatus getConnectionStatus() {
return _connectionReceiver.getConnectionStatus();
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasObserver( ConnectionRequestObserver aObserver ) {
return _observable.hasObserver( aObserver );
}
/**
* {@inheritDoc}
*/
@Override
public boolean isClosable() {
return _connectionReceiver.isClosable();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isClosed() {
return _connectionReceiver.isClosed();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isOpenable( CON aConnection ) {
return _connectionReceiver.isOpenable( aConnection );
}
/**
* {@inheritDoc}
*/
@Override
public boolean isOpened() {
return _connectionReceiver.isOpened();
}
/**
* {@inheritDoc}
*/
@Override
public void open( CON aConnection ) throws IOException {
try {
_observable.fireEvent( new OpenEvent<>( _eventMetaData, _source ) );
}
catch ( VetoException aException ) {
throw new IOException( aException );
}
_connectionReceiver.open( aConnection );
try {
_observable.fireEvent( new OpenedEvent<>( _eventMetaData, _source ) );
}
catch ( VetoException e ) {
/* Cannot happen here */
}
}
/**
* {@inheritDoc}
*/
@Override
public DATA receive() throws IOException {
return _connectionReceiver.receive();
}
/**
* {@inheritDoc}
*/
@Override
public boolean subscribeObserver( ConnectionRequestObserver aObserver ) {
return _observable.subscribeObserver( aObserver );
}
/**
* {@inheritDoc}
*/
@Override
public boolean unsubscribeObserver( ConnectionRequestObserver aObserver ) {
return _observable.unsubscribeObserver( aObserver );
}
// /////////////////////////////////////////////////////////////////////////
// HELPER:
// /////////////////////////////////////////////////////////////////////////
@SuppressWarnings("unchecked")
private CON toSource() {
try {
final Field theField = getClass().getField( "_source" );
if ( theField.getGenericType() instanceof Class> theClass ) {
return theClass.isAssignableFrom( getClass() ) ? (CON) this : null;
}
}
catch ( Exception ignore ) { /* ignore */ }
return null;
}
// /////////////////////////////////////////////////////////////////////////
// INNER CLASSES:
// /////////////////////////////////////////////////////////////////////////
private class ConnectionObservable extends AbstractObservable, ConnectionEvent, CON>> {
// /////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////
private final ExecutionStrategy _executionStrategy;
// /////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////
/**
* Instantiates a new connection observable.
*/
public ConnectionObservable() {
_executionStrategy = ExecutionStrategy.SEQUENTIAL;
}
/**
* Instantiates a new connection observable.
*
* @param aExecutorService the executor service
* @param aExecutionStrategy the execution strategy
*/
public ConnectionObservable( ExecutorService aExecutorService, ExecutionStrategy aExecutionStrategy ) {
super( aExecutorService );
_executionStrategy = ( aExecutionStrategy != null ) ? aExecutionStrategy : ExecutionStrategy.SEQUENTIAL;
}
// /////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
public void clear() {
super.clear();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
return super.isEmpty();
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return super.size();
}
// /////////////////////////////////////////////////////////////////////
// HOOKS:
// /////////////////////////////////////////////////////////////////////
/**
* Same as {@link #fireEvent(ConnectionStatusEvent, ExecutionStrategy)}
* with a predefined {@link ExecutionStrategy}.
*
* @param aEvent the event to be fired.
*
* @return Returns true, if dispatching the event was successful.
*
* @throws VetoException Thrown in case there was a veto.
*
* @see #fireEvent(ConnectionStatusEvent, ExecutionStrategy)
*/
protected boolean fireEvent( ConnectionEvent, CON> aEvent ) throws VetoException {
return super.fireEvent( aEvent, _executionStrategy );
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
protected boolean fireEvent( ConnectionEvent, CON> aEvent, ConnectionRequestObserver aObserver, ExecutionStrategy aExecutionStrategy ) throws Exception {
if ( aEvent instanceof OpenEvent ) {
aObserver.onOpenEvent( (OpenEvent) aEvent );
}
else if ( aEvent instanceof CloseEvent ) {
aObserver.onCloseEvent( (CloseEvent) aEvent );
}
else if ( aEvent instanceof OpenedEvent ) {
aObserver.onOpendEvent( (OpenedEvent) aEvent );
}
else if ( aEvent instanceof ClosedEvent ) {
aObserver.onClosedEvent( (ClosedEvent) aEvent );
}
aObserver.onEvent( (ConnectionEvent) aEvent );
return true;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy