package org.jacorb.events;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.util.LinkedList;
import org.omg.CosEventComm.PullConsumer;
/**
* Implementation of COSEventChannelAdmin interface; ProxyPullSupplier.
* This defines connect_pull_consumer(), disconnect_pull_supplier() and the all
* important pull() and try_pull() methods that the Consumer can call to
* actuall deliver a message.
*
* 2002/23/08 JFC OMG EventService Specification 1.1 page 2-7 states:
* "Registration is a two step process. An event-generating application
* first obtains a proxy consumer from a channel, then 'connects' to the
* proxy consumer by providing it with a supplier. ... The reason for
* the two step registration process..."
* Modifications to support the above have been made as well as to support
* section 2.1.5 "Disconnection Behavior" on page 2-4.
*
* @author Jeff Carlson
* @author Joerg v. Frantzius
* @author Rainer Lischetzki
* @author Gerald Brose
*/
public class ProxyPullSupplierImpl
extends org.omg.CosEventChannelAdmin.ProxyPullSupplierPOA
{
private EventChannelImpl myEventChannel = null;
private PullConsumer myPullConsumer = null;
private org.omg.PortableServer.POA myPoa = null;
private boolean connected = false;
private LinkedList pendingEvents = new LinkedList();
private final int maxListSize = 200;
private static org.omg.CORBA.Any undefinedAny = null;
/**
* Constructor - to be called by EventChannel
*/
protected ProxyPullSupplierImpl ( EventChannelImpl ec,
org.omg.CORBA.ORB orb,
org.omg.PortableServer.POA poa )
{
myEventChannel = ec;
myPoa = poa;
connected = false;
_this_object(orb);
undefinedAny = org.omg.CORBA.ORBSingleton.init().create_any();
}
/**
* ProxyPullSupplier Interface:
* As stated by the EventService specification 1.1 section 2.3.5:
* "If a ProxyPullSupplier is already connected to a PullConsumer, then the
* AlreadyConnected exception is raised."
* and
* "If a non-nil reference is passed to connect_push_supplier..." implying
* that a null reference is acceptable.
*/
public void connect_pull_consumer ( PullConsumer pullConsumer )
throws org.omg.CosEventChannelAdmin.AlreadyConnected
{
if ( connected ) { throw new org.omg.CosEventChannelAdmin.AlreadyConnected(); }
myPullConsumer = pullConsumer;
connected = true;
}
/**
* See EventService v 1.1 specification section 2.1.3.
* 'disconnect_pull_supplier terminates the event communication; it releases
* resources used at the consumer to support event communication. Calling
* this causes the implementation to call disconnect_pull_consumer operation
* on the corresponding PullConsumer interface (if that iterface is known).'
* See EventService v 1.1 specification section 2.1.5. This method should
* adhere to the spec as it a) causes a call to the corresponding disconnect
* on the connected supplier, b) 'If a consumer or supplier has received a
* disconnect call and subsequently receives another disconnect call, it
* shall raise a CORBA::OBJECT_NOT_EXIST exception.
* See EventService v 1.1 specification section 2.3.5. If [a nil object
* reference is passed to connect_pull_consumer] a channel cannot invoke a
* disconnect_pull_consumer operation on the consumer.
*/
public void disconnect_pull_supplier()
{
if ( connected )
{
if ( myPullConsumer != null )
{
myPullConsumer.disconnect_pull_consumer();
myPullConsumer = null;
}
connected = false;
}
else
{
throw new org.omg.CORBA.OBJECT_NOT_EXIST();
}
}
/**
* PullSupplier Interface.
* section 2.1.3 states that "The <b>pull</b> operation blocks until the
* event data is available or an exception is raised. It returns data to
* the consumer."
*/
public org.omg.CORBA.Any pull ()
throws org.omg.CosEventComm.Disconnected
{
org.omg.CORBA.Any event = null;
org.omg.CORBA.BooleanHolder hasEvent = new org.omg.CORBA.BooleanHolder();
while ( true )
{
event = try_pull( hasEvent );
if ( hasEvent.value )
{
return event;
}
Thread.yield();
}
}
/**
* PullSupplier Interface.
* section 2.1.3 states that "The <b>try_pull</b> operation does not block:
* if the event data is available, it returns the event data and sets the
* <b>has_event</b> parameter to true; if the event is not available, it
* sets the <b>has_event</b> parameter to false and the event data is
* returned as long with an undefined value.
* It seems that the event queue should be defined as a LIFO queue. Finton
* Bolton in his book Pure CORBA states that this is the "norm". I think
* that is really stupid. Who wants events in reverse order with a
* possibility of never getting the first messge? I will therefore implement
* this as a FIFO queue and wait for someone to convince me otherwise.
*/
public org.omg.CORBA.Any try_pull ( org.omg.CORBA.BooleanHolder hasEvent )
throws org.omg.CosEventComm.Disconnected
{
if ( !connected ) { throw new org.omg.CosEventComm.Disconnected(); }
org.omg.CORBA.Any event = null;
synchronized( pendingEvents )
{
int listSize = pendingEvents.size();
if ( listSize > 0 )
{
event = (org.omg.CORBA.Any)pendingEvents.getFirst();
pendingEvents.remove( event );
hasEvent.value = true;
return event;
}
else
{
hasEvent.value = false;
return undefinedAny;
}
}
}
/**
* Have to be able to get to the internal list of events. This is how
* to add stuff to this list.
* I have to decide whether to a) just ignore the event, b) add the event
* to the queue and remove the oldest event, c) throw an runtime exception.
* Right now, I'm going with option b.
*/
public void push_to_supplier( org.omg.CORBA.Any event)
{
synchronized( pendingEvents )
{
if ( pendingEvents.size() > maxListSize )
{
pendingEvents.remove( pendingEvents.getFirst() );
}
pendingEvents.add( event );
}
}
/**
* Override this method from the Servant baseclass. Fintan Bolton
* in his book "Pure CORBA" suggests that you override this method to
* avoid the risk that a servant object (like this one) could be
* activated by the <b>wrong</b> POA object.
*/
public org.omg.PortableServer.POA _default_POA()
{
return myPoa;
}
}