home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / fnb101.zip / Lib / site-packages / Fnorb / orb / GIOPServer.py < prev    next >
Text File  |  1999-06-28  |  11KB  |  355 lines

  1. #!/usr/bin/env python
  2. #############################################################################
  3. # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999
  4. # All Rights Reserved.
  5. #
  6. # The software contained on this media is the property of the DSTC Pty
  7. # Ltd.  Use of this software is strictly in accordance with the
  8. # license agreement in the accompanying LICENSE.HTML file.  If your
  9. # distribution of this software does not contain a LICENSE.HTML file
  10. # then you have no rights to use this software in any manner and
  11. # should contact DSTC at the address below to determine an appropriate
  12. # licensing arrangement.
  13. #      DSTC Pty Ltd
  14. #      Level 7, GP South
  15. #      Staff House Road
  16. #      University of Queensland
  17. #      St Lucia, 4072
  18. #      Australia
  19. #      Tel: +61 7 3365 4310
  20. #      Fax: +61 7 3365 4311
  21. #      Email: enquiries@dstc.edu.au
  22. # This software is being provided "AS IS" without warranty of any
  23. # kind.  In no event shall DSTC Pty Ltd be liable for damage of any
  24. # kind arising out of or in connection with the use or performance of
  25. # this software.
  26. #
  27. # Project:      Fnorb
  28. # File:         $Source: /units/arch/src/Fnorb/orb/RCS/GIOPServer.py,v $
  29. # Version:      @(#)$RCSfile: GIOPServer.py,v $ $Revision: 1.11 $
  30. #
  31. #############################################################################
  32. """ GIOPServer class. """
  33.  
  34.  
  35. # Fnorb modules.
  36. import fnorb_thread, CORBA, GIOP, GIOPServerWorker, OctetStream, Util
  37.  
  38.  
  39. class GIOPServer:
  40.     """ GIOPServer class. """
  41.  
  42.     def __init__(self, connection):
  43.     """ Constructor.
  44.  
  45.     'connection' is a connection to a remote ORB.
  46.  
  47.     """
  48.     # Get the object adapter used by the ORB.
  49.     #
  50.     # fixme: We get a reference to the object adapter here for the sake
  51.     # of efficiency, but is this dynamic enough?
  52.     #
  53.     # fixme: Should this be passed as a parameter to the constructor?
  54.     self.__oa = CORBA.ORB_init()._fnorb_object_adapter()
  55.  
  56.     # Get a reference to the factory for GIOP server workers.
  57.     cwf = GIOPServerWorker.GIOPServerWorkerFactory_init()
  58.  
  59.     # Create a new GIOP server worker (the concrete type of which will
  60.     # be determined by the threading model).
  61.     self.__worker = cwf.create_worker(self, connection)
  62.  
  63.     # Flag set when our worker is closed.
  64.     self.__closed = 0
  65.  
  66.     # A mutex to make access to the server thread-safe.
  67.     self.__lk = fnorb_thread.allocate_lock()
  68.  
  69.     return
  70.  
  71.     def pseudo__del__(self):
  72.     """ Pseudo destructor to remove circular references. """
  73.  
  74.     self.__lk.acquire()
  75.  
  76.     # Remove the (circular) reference to our worker.
  77.     del self.__worker
  78.  
  79.     # All done!
  80.     self.__closed = 1
  81.  
  82.     self.__lk.release()
  83.  
  84.     return
  85.  
  86.     #########################################################################
  87.     # GIOPServer interface.
  88.     #########################################################################
  89.  
  90.     def process_giop_message(self, message):
  91.     """ Process a GIOP message.
  92.  
  93.     This method is called by our worker when it has received a GIOP
  94.     message.
  95.  
  96.     """
  97.     # Get a cursor for the message.
  98.     cursor = message.cursor()
  99.  
  100.     # Get the GIOP message header.
  101.     giop_header = message.header()
  102.  
  103.     # Make sure that the header has the right magic and that we are talking
  104.     # the same version of GIOP.
  105.     if giop_header.magic != Util.MAGIC \
  106.        or giop_header.GIOP_version.major != Util.GIOP_VERSION_MAJOR \
  107.        or giop_header.GIOP_version.minor != Util.GIOP_VERSION_MINOR:
  108.         self.__message_error()
  109.  
  110.     # Handle each GIOP message type.
  111.     elif giop_header.message_type == GIOP.Request.value():
  112.         # Unmarshal the GIOP request header.
  113.         tc = CORBA.typecode('IDL:omg.org/GIOP/RequestHeader:1.0')
  114.         request_header = tc._fnorb_unmarshal_value(cursor)
  115.  
  116.         # Pass the message to the active OA to invoke the operation on the
  117.         # appropriate object implementation. The OA will call one of
  118.         # our callback methods iff there is a reply to send.
  119.         self.__oa._fnorb_request((self, request_header, cursor))
  120.         
  121.     elif giop_header.message_type == GIOP.CancelRequest.value():
  122.         # fixme: We just ignore these at the moment!
  123.         pass
  124.  
  125.     elif giop_header.message_type == GIOP.LocateRequest.value():
  126.         # Unmarshal the GIOP locate request header.
  127.         tc = CORBA.typecode('IDL:omg.org/GIOP/LocateRequestHeader:1.0')
  128.         request_header = tc._fnorb_unmarshal_value(cursor)
  129.  
  130.         # See if the object is here!
  131.         if self.__oa._fnorb_object_here(request_header.object_key):
  132.         status = GIOP.OBJECT_HERE
  133.         else:
  134.         status = GIOP.UNKNOWN_OBJECT
  135.  
  136.         # Create and send the locate reply.
  137.         self.__locate_reply(request_header, status)
  138.  
  139.     elif giop_header.message_type == GIOP.MessageError.value():
  140.         # What can we do here?  Just ignore the message!
  141.         pass
  142.  
  143.     # Some crappy message or other ;^)
  144.     else:
  145.         self.__message_error()
  146.     
  147.     return
  148.  
  149.     def close_connection(self):
  150.     """ Close down the connection.
  151.  
  152.     Currently, Fnorb does not close down servers, so this is not used.
  153.  
  154.     """
  155.      # Send the close connection message.
  156.      self.__close_connection()
  157.  
  158.     # In multi-thread mode, if the client has disconnected then the worker
  159.     # will be 'None'.
  160.     worker = self.__get_worker()
  161.     if worker is not None:
  162.         worker.close_connection()
  163.  
  164.     return
  165.     
  166.     #########################################################################
  167.     # Object adapter callback interface.
  168.     #########################################################################
  169.  
  170.     def reply(self, request_header, server_request):
  171.     """ Create and send a successful reply message. """
  172.  
  173.     # Start the reply.
  174.     reply = OctetStream.GIOPMessage(type=GIOP.Reply)
  175.     cursor = reply.cursor()
  176.  
  177.     # Create the reply header.
  178.     reply_header = GIOP.ReplyHeader(request_header.service_context,
  179.                     request_header.request_id,
  180.                     GIOP.NO_EXCEPTION)
  181.  
  182.     # Marshal it onto the octet stream.
  183.     tc = CORBA.typecode('IDL:omg.org/GIOP/ReplyHeader:1.0')
  184.     tc._fnorb_marshal_value(cursor, reply_header)
  185.  
  186.     # Marshal the results onto the octet stream.
  187.     self.__marshal_results(cursor,
  188.                    server_request.outputs(),
  189.                    server_request._fnorb_results())
  190.     # Send it!
  191.     self.__send(reply)
  192.  
  193.     return
  194.  
  195.     def user_exception(self, request_header, server_request):
  196.     """ Create and send a user exception reply message. """
  197.  
  198.     # Start the reply.
  199.     reply = OctetStream.GIOPMessage(type=GIOP.Reply)
  200.     cursor = reply.cursor()
  201.  
  202.     # Create the reply header.
  203.     reply_header = GIOP.ReplyHeader(request_header.service_context,
  204.                     request_header.request_id,
  205.                     GIOP.USER_EXCEPTION)
  206.  
  207.     # Marshal it onto the octet stream.
  208.     tc = CORBA.typecode('IDL:omg.org/GIOP/ReplyHeader:1.0')
  209.     tc._fnorb_marshal_value(cursor, reply_header)
  210.  
  211.     # Get the exception that was raised in response to the server request.
  212.     ex = server_request._fnorb_exception()
  213.  
  214.     # Try to find a matching exception.
  215.     for typecode in server_request.exceptions():
  216.         if ex._FNORB_ID == typecode.id():
  217.         break
  218.  
  219.     # If there is no matching exception then raise an 'UNKNOWN' system
  220.     # exception.
  221.     else:
  222.         raise CORBA.UNKNOWN() # System exception.
  223.  
  224.     # Marshal the repository id of the exception followed by its members.
  225.     cursor.marshal('s', typecode.id())
  226.     typecode._fnorb_marshal_value(cursor, ex)
  227.  
  228.     # Send it.
  229.     self.__send(reply)
  230.  
  231.     return
  232.     
  233.     def system_exception(self, request_header, ex):
  234.     """ Create and send a system exception reply message. """
  235.  
  236.     # Create an octet stream and get a cursor for it.
  237.     reply = OctetStream.GIOPMessage(type=GIOP.Reply)
  238.     cursor = reply.cursor()
  239.  
  240.     # Create the reply header.
  241.     reply_header = GIOP.ReplyHeader(request_header.service_context,
  242.                     request_header.request_id,
  243.                     GIOP.SYSTEM_EXCEPTION)
  244.  
  245.     # Marshal it onto the octet stream.
  246.     tc = CORBA.typecode('IDL:omg.org/GIOP/ReplyHeader:1.0')
  247.     tc._fnorb_marshal_value(cursor, reply_header)
  248.  
  249.     # Marshal the system exception onto the octet stream.
  250.     cursor.marshal('s', "IDL:omg.org/CORBA/%s:1.0" % ex.__class__.__name__)
  251.     ex._fnorb_marshal(cursor)
  252.  
  253.     # Send it.
  254.     self.__send(reply)
  255.  
  256.     return
  257.  
  258.     #########################################################################
  259.     # Private interface.
  260.     #########################################################################
  261.  
  262.     def __get_worker(self):
  263.     """ Get our GIOP server worker. """
  264.  
  265.     self.__lk.acquire()
  266.     try:
  267.         if self.__closed:
  268.         worker = None
  269.  
  270.         else:
  271.         worker = self.__worker
  272.  
  273.     finally:
  274.         self.__lk.release()
  275.  
  276.       return worker
  277.  
  278.     def __send(self, message):
  279.     """ Send a GIOP message via our worker. """
  280.  
  281.     # In multi-thread mode, if the client has disconnected before we have
  282.     # had a chance to send the reply, then the worker will be 'None'.
  283.     worker = self.__get_worker()
  284.     if worker is not None:
  285.         worker.send(message)
  286.  
  287.     return
  288.  
  289.     def __marshal_results(self, cursor, typecodes, results):
  290.     """ Marshal the results of a request onto an octet stream. """
  291.  
  292.     no_of_outputs = len(typecodes)
  293.  
  294.     # If there are no outputs then do nothing ;^)
  295.     if no_of_outputs == 0:
  296.         pass
  297.  
  298.     # If there is exactly 1 result from the request then 'results'
  299.     # contains a single value.
  300.     elif no_of_outputs == 1:
  301.         # Marshal the first and only output!
  302.         typecodes[0]._fnorb_marshal_value(cursor, results)
  303.  
  304.     # Otherwise, 'results' is a tuple containing all of the results.
  305.     else:
  306.         i = 0
  307.         for typecode in typecodes:
  308.         typecode._fnorb_marshal_value(cursor, results[i])
  309.         i = i + 1
  310.  
  311.     return
  312.  
  313.     def __locate_reply(self, request_header, status):
  314.     """ Create and send a locate reply. """
  315.  
  316.     # Start the reply.
  317.     message = OctetStream.GIOPMessage(type=GIOP.LocateReply)
  318.     cursor = message.cursor()
  319.  
  320.     # Create the locate reply header and marshal it onto the octet stream.
  321.     reply_header = GIOP.LocateReplyHeader(request_header.request_id,status)
  322.     tc = CORBA.typecode('IDL:omg.org/GIOP/LocateReplyHeader:1.0')
  323.     tc._fnorb_marshal_value(cursor, reply_header)
  324.  
  325.     # Send it!
  326.     self.__send(message)
  327.  
  328.     return
  329.  
  330.     def __message_error(self):
  331.     """ Create and send a 'MessageError' message. """
  332.  
  333.     # Create the 'MessageError' message.
  334.     message = OctetStream.GIOPMessage(type=GIOP.MessageError)
  335.  
  336.     # Send it!
  337.     self.__send(message)
  338.  
  339.     return
  340.  
  341.     def __close_connection(self):
  342.     """ Create and send a close connection message. """
  343.  
  344.     # Create the 'CloseConnection' message.
  345.     message = OctetStream.GIOPMessage(type=GIOP.CloseConnection)
  346.  
  347.     # Send it!
  348.     self.__send(message)
  349.  
  350.     return
  351.  
  352. #############################################################################
  353.