/*
* This file is protected by Copyright. Please refer to the COPYRIGHT file
* distributed with this source distribution.
*
* This file is part of REDHAWK core.
*
* REDHAWK core 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 3 of the License, or (at your
* option) any later version.
*
* REDHAWK core 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 program. If not, see http://www.gnu.org/licenses/.
*/
package org.ossie.events;
import java.util.Queue;
import java.util.LinkedList;
import org.apache.log4j.Logger;
import org.omg.CORBA.ORB;
import org.omg.CORBA.Any;
import org.omg.CORBA.*;
import org.omg.CosEventComm.*;
import org.omg.CosEventChannelAdmin.*;
import CF.EventChannelManagerPackage.*;
import org.ossie.properties.AnyUtils;
import java.lang.InterruptedException;
import java.util.concurrent.locks.*;
import java.util.concurrent.TimeUnit;
public class Subscriber {
public abstract class EventSubscriberConsumer extends PushConsumerPOA {
};
public interface DataArrivedListener {
public void processData( final Any data );
};
public abstract class Receiver extends PushConsumerPOA {
public Receiver() {};
public boolean get_disconnect() { return _recv_disconnect; };
public void reset() { _recv_disconnect = false; };
public void disconnect_push_consumer () {
_logger.debug("::disconnect_push_consumer handle disconnect_push_supplier." );
_lock.lock();
try{
_recv_disconnect = true;
_cond.signalAll();
}finally {
_lock.unlock();
}
};
public void wait_for_disconnect ( int wait_time, int retries )
{
int tries=retries;
_lock.lock();
try {
while( _recv_disconnect == false ) {
if ( wait_time > -1 ) {
_logger.debug("::wait_for_disconnect.. Waiting on disconnect." );
boolean ret = false;
try {
ret= _cond.await( wait_time, TimeUnit.MILLISECONDS );
} catch( InterruptedException e ) {
}
if ( !ret && tries == -1 ) {
break;
}
if ( tries-- < 1 ) break;
}
else {
try {
_cond.await();
} catch( InterruptedException e ) {
}
}
}
} finally {
_lock.unlock();
}
return;
};
protected Lock _lock = new ReentrantLock();
protected Condition _cond = _lock.newCondition();
protected boolean _recv_disconnect = true;
protected Logger _logger = Logger.getLogger("ossie.events.Subscriber.Receiver");
};
private class DefaultConsumer extends Receiver {
public DefaultConsumer ( Subscriber inParent ) {
parent = inParent;
}
public void push( final org.omg.CORBA.Any data ) {
_logger.trace(" received data from event channel ..");
if ( parent != null ) {
// if parent defines a callback
if ( parent.dataArrivedCB != null ) {
// RESOLVE need to allow for Generic callback method to convert data and
// push data...
try{
parent.dataArrivedCB.processData( data );
}
catch( Throwable e){
}
}
else {
parent.events.add(data);
}
};
};
private Subscriber parent;
};
//
// Subscriber for an Event Channel
//
// @param channel event channel returned from the EventChannelManager
// @param pub interface that is notified when a disconnect occurs
// @param retries number of retries to perform when trying to establish publisher interface
// @param retry_wait number of millisecs to wait between retries
public Subscriber( EventChannel inChannel )
throws OperationNotAllowed
{
this(inChannel,null );
}
public Subscriber( EventChannel inChannel,
DataArrivedListener newListener )
throws OperationNotAllowed
{
_init( inChannel, newListener );
}
public int getData( Any ret ) {
int retval=-1;
try{
// check if callback method is enable.. it so then return
if ( dataArrivedCB != null ) return retval;
// check if data is available
if ( events.size() < 1 ) return retval;
Any rawdata = events.remove();
ret.read_value(rawdata.create_input_stream(),rawdata.type());
retval=0;
}
catch( Throwable e) {
}
return retval;
}
public Any getData() {
Any retval=null;
try{
// check if callback method is enable.. it so then return
if ( dataArrivedCB != null ) return retval;
// check if data is available
if ( events.size() < 1 ) return retval;
return events.remove();
}
catch( Throwable e) {
}
return retval;
}
public void setDataArrivedListener( DataArrivedListener newListener ) {
dataArrivedCB = newListener;
}
public void terminate () {
logger.trace("Subscriber: TERMINATE START" );
if ( consumer != null ) {
org.ossie.corba.utils.deactivateObject(consumer);
}
disconnect();
proxy = null;
consumer = null;
logger.trace("Subscriber: TERMINATE END." );
}
public int disconnect() {
return this.disconnect(10,10);
}
public int disconnect( int retries, int retry_wait ) {
logger.debug("Subscriber: disconnect ....." );
int retval = -1;
int tries = retries;
if ( proxy != null ) {
do {
try {
logger.debug("Subscriber: disconnect_push_supplier... ");
proxy.disconnect_push_supplier();
retval=0;
break;
}
catch (COMM_FAILURE ex) {
logger.warn("Caught COMM_FAILURE Exception, diconnecting Push Consumer for Subscriber, Retrying..." );
}
if ( retry_wait > 0 ) {
try {
java.lang.Thread.sleep(retry_wait*1000);
} catch (final InterruptedException ex) {
}
}
tries--;
} while(tries>0);
if ( consumer != null ){
logger.debug("Subscriber::disconnect Waiting for disconnect ........" );
consumer.wait_for_disconnect(1,3);
logger.debug("Subscriber::disconnect received disconnect." );
}
logger.debug("Subscriber: ProxyPushSupplier disconnected." );
}
return retval;
}
public int connect() {
return this.connect(10,10);
}
public int connect( int retries, int retry_wait ) {
int retval=-1;
int tries=retries;
if ( channel == null ) {
logger.warn( "Subscriber, Channel resource not available ");
return retval;
}
if ( proxy == null ) {
ConsumerAdmin admin=null;
do {
try {
logger.debug( "Subscriber, Grab admin object...");
admin = channel.for_consumers ();
break;
}
catch (COMM_FAILURE ex) {
}
if ( retry_wait > 0 ) {
try {
java.lang.Thread.sleep(retry_wait*1000);
} catch (final InterruptedException ex) {
}
}
tries--;
} while ( tries > 0 );
if ( admin == null ) return retval;
logger.debug( "Subscriber, Obtained ConsumerAdmin...");
tries=retries;
do {
try {
logger.debug( "Subscriber, Grab push supplier proxy.");
proxy = admin.obtain_push_supplier();
break;
}
catch (COMM_FAILURE ex) {
}
if ( retry_wait > 0 ) {
try {
java.lang.Thread.sleep(retry_wait*1000);
} catch (final InterruptedException ex) {
}
}
tries--;
} while ( tries > 0 );
logger.debug( "Subscriber, Obtained ProxyPushConsumer." );
}
if ( proxy == null ) return retval;
PushConsumer sptr=null;
if ( consumer != null ) {
try {
org.omg.PortableServer.POA poa = org.ossie.corba.utils.OrbContext.RootPOA();
org.omg.CORBA.Object consumer_obj = poa.servant_to_reference(consumer);
sptr = PushConsumerHelper.narrow(consumer_obj);
}
catch(org.omg.PortableServer.POAPackage.ServantNotActive ex) {
logger.error( "Subscriber, Caught ServantNotActive exception connecting Push Consumer!");
}
catch(org.omg.PortableServer.POAPackage.WrongPolicy ex) {
logger.error( "Subscriber, Caught WrongPolicy exception connecting Push Consumer!");
}
}
// now attach supplier to the proxy
tries=retries;
do {
try {
proxy.connect_push_consumer( sptr );
if ( consumer != null ) {
logger.debug( "Subscriber, Reset consumer state ....." );
consumer.reset();
}
logger.debug( "Subscriber, Connected Consumer to EventChannel....." );
retval=0;
break;
}
catch(TypeError ex) {
logger.error( "Subscriber, Caught TypeError exception connecting Push Consumer!");
break;
}
catch(BAD_PARAM ex) {
logger.error( "Subscriber, Caught BAD_PARAM exception connecting Push Consumer!");
break;
}
catch(AlreadyConnected ex) {
logger.warn( "Subscriber, Push Consumer already connected!");
consumer.reset();
retval=0;
break;
}
catch(COMM_FAILURE ex) {
logger.error( "Subscriber, Caught COMM_FAILURE exception "
+"connecting Push Supplier! Retrying...");
}
if ( retry_wait > 0 ) {
try {
java.lang.Thread.sleep(retry_wait*1000);
} catch (final InterruptedException ex) {
}
}
tries--;
} while ( tries > 0);
return retval;
};
// handle to the Event Channel ... duplicate the channel so we own this object
protected EventChannel channel;
// handle to object that publishes the event to the channel's consumers
//protected ProxyPushSupplierOperations proxy;
protected ProxyPushSupplier proxy;
// handle to object that responds to disconnect messages
protected Receiver consumer;
//
// Logger object
//
protected Logger logger=null;
//
// Callback interface when event messages arrive
//
protected DataArrivedListener dataArrivedCB=null;
protected Queue< Any > events=null;
private void _init( EventChannel inChannel, DataArrivedListener newListener )
throws OperationNotAllowed
{
logger = Logger.getLogger("ossie.events.Subscriber");
dataArrivedCB = newListener;
// create queue to hold events
events = new LinkedList< Any >();
// if user passes a bad param then throw...
channel=inChannel;
if ( inChannel == null ) throw new OperationNotAllowed();
// create a local consumer object for the event channel
consumer = new DefaultConsumer(this);
if ( consumer != null ) {
org.ossie.corba.utils.activateObject(consumer, null);
}
// connect to the event channel for a subscriber pattern
connect();
}
};