001: package org.jacorb.events;
002:
003: /*
004: * JacORB - a free Java ORB
005: *
006: * Copyright (C) 1997-2004 Gerald Brose.
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Library General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Library General Public License for more details.
017: *
018: * You should have received a copy of the GNU Library General Public
019: * License along with this library; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: */
022:
023: import org.omg.CosEventComm.*;
024: import org.jacorb.orb.*;
025: import java.util.*;
026:
027: /**
028: * Implementation of COSEventChannelAdmin interface; ProxyPullSupplier.
029: * This defines connect_pull_consumer(), disconnect_pull_supplier() and the all
030: * important pull() and try_pull() methods that the Consumer can call to
031: * actuall deliver a message.
032: *
033: * 2002/23/08 JFC OMG EventService Specification 1.1 page 2-7 states:
034: * "Registration is a two step process. An event-generating application
035: * first obtains a proxy consumer from a channel, then 'connects' to the
036: * proxy consumer by providing it with a supplier. ... The reason for
037: * the two step registration process..."
038: * Modifications to support the above have been made as well as to support
039: * section 2.1.5 "Disconnection Behavior" on page 2-4.
040: *
041: * @author Jeff Carlson
042: * @author Joerg v. Frantzius
043: * @author Rainer Lischetzki
044: * @author Gerald Brose
045: * @version $Id: ProxyPullSupplierImpl.java,v 1.11 2004/05/06 12:39:58 nicolas Exp $
046: */
047: public class ProxyPullSupplierImpl extends
048: org.omg.CosEventChannelAdmin.ProxyPullSupplierPOA {
049: private EventChannelImpl myEventChannel = null;
050: private PullConsumer myPullConsumer = null;
051: private org.omg.PortableServer.POA myPoa = null;
052: private boolean connected = false;
053: private LinkedList pendingEvents = new LinkedList();
054: private final int maxListSize = 200;
055: private static org.omg.CORBA.Any undefinedAny = null;
056:
057: /**
058: * Constructor - to be called by EventChannel
059: */
060: protected ProxyPullSupplierImpl(EventChannelImpl ec,
061: org.omg.CORBA.ORB orb, org.omg.PortableServer.POA poa) {
062: myEventChannel = ec;
063: myPoa = poa;
064: connected = false;
065: _this _object(orb);
066: undefinedAny = org.omg.CORBA.ORB.init().create_any();
067: }
068:
069: /**
070: * ProxyPullSupplier Interface:
071: * As stated by the EventService specification 1.1 section 2.3.5:
072: * "If a ProxyPullSupplier is already connected to a PullConsumer, then the
073: * AlreadyConnected exception is raised."
074: * and
075: * "If a non-nil reference is passed to connect_push_supplier..." implying
076: * that a null reference is acceptable.
077: */
078:
079: public void connect_pull_consumer(PullConsumer pullConsumer)
080: throws org.omg.CosEventChannelAdmin.AlreadyConnected {
081: if (connected) {
082: throw new org.omg.CosEventChannelAdmin.AlreadyConnected();
083: }
084: myPullConsumer = pullConsumer;
085: connected = true;
086: }
087:
088: /**
089: * See EventService v 1.1 specification section 2.1.3.
090: * 'disconnect_pull_supplier terminates the event communication; it releases
091: * resources used at the consumer to support event communication. Calling
092: * this causes the implementation to call disconnect_pull_consumer operation
093: * on the corresponding PullConsumer interface (if that iterface is known).'
094: * See EventService v 1.1 specification section 2.1.5. This method should
095: * adhere to the spec as it a) causes a call to the corresponding disconnect
096: * on the connected supplier, b) 'If a consumer or supplier has received a
097: * disconnect call and subsequently receives another disconnect call, it
098: * shall raise a CORBA::OBJECT_NOT_EXIST exception.
099: * See EventService v 1.1 specification section 2.3.5. If [a nil object
100: * reference is passed to connect_pull_consumer] a channel cannot invoke a
101: * disconnect_pull_consumer operation on the consumer.
102: */
103:
104: public void disconnect_pull_supplier() {
105: if (connected) {
106: if (myPullConsumer != null) {
107: myPullConsumer.disconnect_pull_consumer();
108: myPullConsumer = null;
109: }
110: connected = false;
111: } else {
112: throw new org.omg.CORBA.OBJECT_NOT_EXIST();
113: }
114: }
115:
116: /**
117: * PullSupplier Interface.
118: * section 2.1.3 states that "The <b>pull</b> operation blocks until the
119: * event data is available or an exception is raised. It returns data to
120: * the consumer."
121: */
122:
123: public org.omg.CORBA.Any pull()
124: throws org.omg.CosEventComm.Disconnected {
125: org.omg.CORBA.Any event = null;
126: org.omg.CORBA.BooleanHolder hasEvent = new org.omg.CORBA.BooleanHolder();
127: while (true) {
128: event = try_pull(hasEvent);
129: if (hasEvent.value) {
130: return event;
131: }
132: Thread.yield();
133: }
134: }
135:
136: /**
137: * PullSupplier Interface.
138: * section 2.1.3 states that "The <b>try_pull</b> operation does not block:
139: * if the event data is available, it returns the event data and sets the
140: * <b>has_event</b> parameter to true; if the event is not available, it
141: * sets the <b>has_event</b> parameter to false and the event data is
142: * returned as long with an undefined value.
143: * It seems that the event queue should be defined as a LIFO queue. Finton
144: * Bolton in his book Pure CORBA states that this is the "norm". I think
145: * that is really stupid. Who wants events in reverse order with a
146: * possibility of never getting the first messge? I will therefore implement
147: * this as a FIFO queue and wait for someone to convince me otherwise.
148: */
149:
150: public org.omg.CORBA.Any try_pull(
151: org.omg.CORBA.BooleanHolder hasEvent)
152: throws org.omg.CosEventComm.Disconnected {
153: if (!connected) {
154: throw new org.omg.CosEventComm.Disconnected();
155: }
156:
157: org.omg.CORBA.Any event = null;
158:
159: synchronized (pendingEvents) {
160: int listSize = pendingEvents.size();
161: if (listSize > 0) {
162: event = (org.omg.CORBA.Any) pendingEvents.getFirst();
163: pendingEvents.remove(event);
164: hasEvent.value = true;
165: return event;
166: } else {
167: hasEvent.value = false;
168: return undefinedAny;
169: }
170: }
171: }
172:
173: /**
174: * Have to be able to get to the internal list of events. This is how
175: * to add stuff to this list.
176: * I have to decide whether to a) just ignore the event, b) add the event
177: * to the queue and remove the oldest event, c) throw an runtime exception.
178: * Right now, I'm going with option b.
179: */
180:
181: public void push_to_supplier(org.omg.CORBA.Any event) {
182: synchronized (pendingEvents) {
183: if (pendingEvents.size() > maxListSize) {
184: pendingEvents.remove(pendingEvents.getFirst());
185: }
186: pendingEvents.add(event);
187: }
188: }
189:
190: /**
191: * Override this method from the Servant baseclass. Fintan Bolton
192: * in his book "Pure CORBA" suggests that you override this method to
193: * avoid the risk that a servant object (like this one) could be
194: * activated by the <b>wrong</b> POA object.
195: */
196:
197: public org.omg.PortableServer.POA _default_POA() {
198: return myPoa;
199: }
200: }
|