#!/usr/bin/env python ############################################################################# # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999 # All Rights Reserved. # # The software contained on this media is the property of the DSTC Pty # Ltd. Use of this software is strictly in accordance with the # license agreement in the accompanying LICENSE.HTML file. If your # distribution of this software does not contain a LICENSE.HTML file # then you have no rights to use this software in any manner and # should contact DSTC at the address below to determine an appropriate # licensing arrangement. # # DSTC Pty Ltd # Level 7, GP South # Staff House Road # University of Queensland # St Lucia, 4072 # Australia # Tel: +61 7 3365 4310 # Fax: +61 7 3365 4311 # Email: enquiries@dstc.edu.au # # This software is being provided "AS IS" without warranty of any # kind. In no event shall DSTC Pty Ltd be liable for damage of any # kind arising out of or in connection with the use or performance of # this software. # # Project: Fnorb # File: $Source: /cvsroot/fnorb/fnorb/orb/GIOPServerWorkerReactive.py,v $ # Version: @(#)$RCSfile: GIOPServerWorkerReactive.py,v $ $Revision: 1.6 $ # ############################################################################# """ GIOPServerWorkerReactive class. """ # Fnorb modules. import CORBA, EventHandler, GIOPServerWorker, GIOPConnectionHandler, Reactor class GIOPServerWorkerReactive(GIOPServerWorker.GIOPServerWorker, EventHandler.EventHandler): """ GIOPServerWorkerReactive class. A concrete 'EventHandler' in the 'Reactor' pattern. This class is *not* thread safe, but since the whole point of the 'Reactor' pattern is to work in a single-threaded environment, I don't see this as much of a problem ;^) """ def __init__(self, giop_version, giop_server, connection): """ Provide an interface to a remote object! 'giop_version' is the GIOP version of this ORB 'giop_server' is the server for the connection 'connection' is the aconnection to the remote object. """ self.__giop_version = giop_version self.__giop_server = giop_server self.__connection = connection # Have we been closed down? self.__closed = 0 # Set the connection to NON-blocking mode. self.__connection.blocking(0) # Queue of outgoing GIOP messages. self.__outgoing = [] # Get a reference to the active reactor. self.__reactor = Reactor.Reactor_init() # Register our interest in read events (ie. operation requests) with # the Reactor. self.__reactor.register_handler(self, Reactor.READ) # Create a handler to look after the connection. self.__handler = GIOPConnectionHandler.GIOPConnectionHandler \ (self.__giop_version, self, self.__connection) return def pseudo__del__(self): """ Pseudo destructor to remove circular references. This method is called from '__shutdown' only. """ # The GIOP server holds a (circular) reference to this instance so we # have to explicitly clean it up. self.__giop_server.pseudo__del__() # Clean up *our* reference to *it*! del self.__giop_server # The handler also holds a (circular) reference to this instance so we # have to explicitly clean it up. self.__handler.pseudo__del__() # Clean up *our* reference to *it*! del self.__handler return ######################################################################### # GIOPServerWorker interface. ######################################################################### def send(self, message): """ Send a message to the 'client'. This method simply adds the message to the queue of outgoing messages and registers out interest in write events with the Reactor. """ # Add the outgoing message to the queue. self.__outgoing.append(message) # Register my interest in write events with the Reactor. self.__reactor.register_handler(self, Reactor.WRITE) return def close_connection(self): """ Close down the worker. Currently, Fnorb does not close down servers, so this is not used. """ if not self.__closed: # Don't accept any more operation requests. self.__reactor.unregister_handler(self, Reactor.READ) # Send all outstanding messages. while len(self.__outgoing) > 0: self.__reactor.do_one_event() # Close down the worker. self.__close() return ######################################################################### # EventHandler interface. ######################################################################### def handle_event(self, mask): """ Callback method to handle all events except close events. """ # Read event. if mask & Reactor.READ: try: self.__handler.recv() except CORBA.SystemException: self.handle_close() # Write event. elif mask & Reactor.WRITE: try: self.__handler.send(self.__outgoing[0]) except CORBA.SystemException: self.handle_close() # Exception event. elif mask & Reactor.EXCEPTION: self.handle_close() return def handle_close(self): """ Callback method to handle close events. """ # Close down the worker. self.__close() return def handle(self): """ Return my underlying I/O handle. In this case, my I/O handle is the file descriptor of my socket. """ return self.__connection.handle() ######################################################################### # GIOPConnectionHandlerListener interface. ######################################################################### def message_received(self, message): """ Called when a complete GIOP message has been received. """ # Pass the message up to the GIOP server. self.__giop_server.process_giop_message(message) return def message_sent(self): """ Called when a complete GIOP message has been sent. """ # Remove the message from the outgoing queue. del self.__outgoing[0] # If there are no other messages left to send then tell the Reactor # that I am no longer interested in write events. if len(self.__outgoing) == 0: self.__reactor.unregister_handler(self, Reactor.WRITE) return ######################################################################### # Private interface. ######################################################################### def __close(self): """ Close down the worker. """ if not self.__closed: # Withdraw all of my Reactor registrations. self.__reactor.unregister_handler(self, Reactor.ALL) # Set the connection to blocking mode. self.__connection.blocking(1) # Close our connection. self.__connection.disconnect() # All done! self.__closed = 1 # Remove circular references. self.pseudo__del__() return #############################################################################