#!/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: /projects/fnorb/Fnorb-1.1/orb/RCS/GIOPServerWorkerThreaded.py,v $
# Version:      @(#)$RCSfile: GIOPServerWorkerThreaded.py,v $ $Revision: 1.6 $
#
#############################################################################
""" GIOPServerWorkerThreaded class. """


# For obvious reasons we import the *real* thread module, not 'fnorb_thread'!
import thread

# Fnorb modules.
import CORBA, GIOPConnectionHandler, GIOPServerWorker


class GIOPServerWorkerThreaded(GIOPServerWorker.GIOPServerWorker):
    """ IIOP Worker class. """

    def __init__(self, giop_server, connection):
	""" Constructor.

	'giop_server' is the GIOPServer server that is creating the worker.
	'connection'  is a connection to the 'client' ORB.

	"""
	self.__giop_server = giop_server
	self.__connection = connection

	# Set the connection to BLOCKING mode.
	self.__connection.blocking(1)
	
	# Create a handler to look after the connection.
	self.__handler = GIOPConnectionHandler.GIOPConnectionHandler \
			 (self, self.__connection)

	# Flag used to detect closure in the worker thread.
	self.__closed = 0

	# Mutex for the '__closed' flag.
	self.__lk = thread.allocate_lock()

	# Start the worker thread.
	thread.start_new_thread(self.__worker_thread, ())

	return

    def pseudo__del__(self):
	""" Pseudo destructor to remove circular references.

	This method is called from '__close' 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. """

	self.__lk.acquire()
	try:
	    try:
		# Send the entire message.
		n = 0
		while n < len(message):
		    n = n + self.__handler.send(message)

	    # We can simply ignore any exceptions when sending a message
	    # as the worker thread will detect the error and close down
	    # the connection.
	    except CORBA.SystemException:
		pass

	finally:
	    self.__lk.release()

    def close_connection(self):
	""" Close down the server.

	Currently, Fnorb does not close down servers, so this is not used.

	"""
	# Close down the worker.
	self.__close()

	return

    #########################################################################
    # GIOPConnectionHandlerListener interface.
    #########################################################################

    def message_received(self, message):
	""" Called when a complete GIOP message has been received. """

	# Pass the message up to the GIOP layer.
	self.__giop_server.process_giop_message(message)

	return

    def message_sent(self):
	""" Called when a complete GIOP message has been sent. """

	pass

    #########################################################################
    # Private interface.
    #########################################################################

    def __worker_thread(self):
	""" Read operation requests from the client. """

	try:
	    while not self.__is_closed():
		# Blocking receive.
		self.__handler.recv()

	except CORBA.SystemException:
	    pass

	# Close down the worker.
	self.__close()

	# Explicitly exit the thread!
	thread.exit()

    def __is_closed(self):
	""" Are we closing down? """

	self.__lk.acquire()
	closed = self.__closed
	self.__lk.release()

	return closed

    def __close(self):
	""" Close down the worker. """

 	# Notify the worker thread that we are closing down.
	self.__lk.acquire()
	try:
	    if not self.__closed:
		# Close down the connection (via the handler)
		self.__connection.disconnect()

		# All done!
		self.__closed = 1

		# Remove circular reference.
		self.pseudo__del__()

	finally:
	    self.__lk.release()

#############################################################################
