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; } }