home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / fnb101.zip / Lib / site-packages / Fnorb / orb / CORBA.py < prev    next >
Text File  |  1999-06-28  |  46KB  |  1,493 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/CORBA.py,v $
  29. # Version:      @(#)$RCSfile: CORBA.py,v $ $Revision: 1.43 $
  30. #
  31. #############################################################################
  32. """ CORBA module. """
  33.  
  34.  
  35. # Fnorb modules.
  36. import fnorb_thread, TypeManager, Util
  37.  
  38.  
  39. # ORB identifier.
  40. ORB_ID = 'The ORB called Fnorb v1.0.Threads.R.Us'
  41.  
  42. # Boolean 'constants' as specified in the Python language mapping.
  43. TRUE  = 1
  44. FALSE = 0
  45.  
  46. #############################################################################
  47. # Exception classes.
  48. #############################################################################
  49.  
  50. # Exception base class.
  51. class CORBAException: pass
  52.  
  53. # User exceptions.
  54. class UserException(CORBAException): pass
  55.  
  56. # System exceptions.
  57. #
  58. # Enum: IDL:omg.org/CORBA/completion_status:1.0
  59. COMPLETED_YES     = Util.EnumMember('COMPLETED_YES',   0)
  60. COMPLETED_NO      = Util.EnumMember('COMPLETED_NO',    1)
  61. COMPLETED_MAYBE   = Util.EnumMember('COMPLETED_MAYBE', 2)
  62. completion_status = Util.Enum("IDL:omg.org/CORBA/completion_status:1.0",
  63.                   [COMPLETED_YES, COMPLETED_NO, COMPLETED_MAYBE])
  64.  
  65. TypeManager.TypeManager_init().add_type("IDL:omg.org/CORBA/completion_status:1.0", "000000000000001100000088000000000000002849444C3A6F6D672E6F72672F434F5242412F636F6D706C6574696F6E5F7374617475733A312E300000000012636F6D706C6574696F6E5F737461747573000000000000030000000E434F4D504C455445445F5945530000000000000D434F4D504C455445445F4E4F0000000000000010434F4D504C455445445F4D4159424500", completion_status)
  66.  
  67. class SystemException(CORBAException):
  68.     """ Struct: IDL:omg.org/CORBA/SystemException:1.0 """
  69.  
  70.     _FNORB_ID = "IDL:omg.org/CORBA/SystemException:1.0"
  71.  
  72.     def __init__(self, _minor=0, _completed=COMPLETED_NO):
  73.         """ Constructor. """
  74.  
  75.         self.minor = _minor
  76.         self.completed = _completed
  77.         return
  78.  
  79.     def __getinitargs__(self):
  80.         """ Return the constructor arguments for unpickling. """
  81.  
  82.         return (self.minor, self.completed)
  83.  
  84.     def __str__(self):
  85.      """ Return a string representation of the exception. """
  86.  
  87.      return 'Minor: ' + `self.minor` + ' Completed: ' + str(self.completed)
  88.  
  89.     # fixme: Replace these methods with typecode marshalling?
  90.     def _fnorb_marshal(self, cursor):
  91.         """ Marshal the structure onto an octet stream. """
  92.  
  93.         cursor.marshal('L', self.minor)
  94.         cursor.marshal('L', self.completed.value())
  95.         return
  96.  
  97.     def _fnorb_unmarshal(self, cursor):
  98.         """ Unmarshal the structure from an octet stream. """
  99.  
  100.         self.minor = cursor.unmarshal('L')
  101.         self.completed = completion_status[int(cursor.unmarshal('L'))]
  102.         return
  103.  
  104. # A class for every system exception!
  105. class UNKNOWN         (SystemException): pass # The unknown exception!
  106. class BAD_PARAM       (SystemException): pass # Invalid parameter was passed.
  107. class NO_MEMORY       (SystemException): pass # Memory allocation failure.
  108. class IMP_LIMIT       (SystemException): pass # Violated implementation limit.
  109. class COMM_FAILURE    (SystemException): pass # Communication failure.
  110. class INV_OBJREF      (SystemException): pass # Invalid object reference.
  111. class NO_PERMISSION   (SystemException): pass # No permission for operation.
  112. class INTERNAL        (SystemException): pass # ORB internal error.
  113. class MARSHAL         (SystemException): pass # Error marshalling param/result.
  114. class INITIALIZE      (SystemException): pass # ORB initialisation failure.
  115. class NO_IMPLEMENT    (SystemException): pass # Op. implementation unavailable.
  116. class BAD_TYPECODE    (SystemException): pass # Bad typecode.
  117. class BAD_OPERATION   (SystemException): pass # Invalid operation.
  118. class NO_RESOURCES    (SystemException): pass # Insufficient resources for req.
  119. class NO_RESPONSE     (SystemException): pass # Response to req. not available.
  120. class PERSIST_STORE   (SystemException): pass # Persistent storage failure.
  121. class BAD_INV_ORDER   (SystemException): pass # Routine inv. out of order
  122. class TRANSIENT       (SystemException): pass # Transient failure, reissue req.
  123. class FREE_MEM        (SystemException): pass # Cannot free memory.
  124. class INV_IDENT       (SystemException): pass # Invalid identifier syntax.
  125. class INV_FLAG        (SystemException): pass # Invalid flag was specified.
  126. class INTF_REPOS      (SystemException): pass # Error accessing I/F repository.
  127. class BAD_CONTEXT     (SystemException): pass # Error processing context obj.
  128. class OBJ_ADAPTER     (SystemException): pass # Failure detected by adapter.
  129. class DATA_CONVERSION (SystemException): pass # Data conversion error.
  130. class OBJECT_NOT_EXIST(SystemException): pass # Non-existent object, del OR.
  131.  
  132. #############################################################################
  133. # The ORB interface.
  134. #############################################################################
  135.  
  136. def ORB_init(argv=[], orb_id=ORB_ID):
  137.     """ Initialise the ORB.
  138.  
  139.     This is a factory function for the ORB class (the ORB is a singleton (ie.
  140.     there can only be one ORB instance per process)).
  141.  
  142.     """
  143.     try:
  144.     orb = ORB(argv, orb_id)
  145.  
  146.     except ORB, orb:
  147.     pass
  148.  
  149.     return orb
  150.  
  151.  
  152. class ORB:
  153.     """ The ORB object.
  154.  
  155.     The ORB is a singleton (ie. there can only be one ORB instance per
  156.     process).
  157.  
  158.     """
  159.     # Singleton instance.
  160.     __instance = None
  161.  
  162.     # Mutex to make access via the factory function thread-safe.
  163.     __lk = fnorb_thread.allocate_lock()
  164.  
  165.     # Exceptions.
  166.     class InvalidName(UserException): pass
  167.  
  168.     def __init__(self, argv, orb_id):
  169.     """ Constructor.
  170.  
  171.     'argv'   command line arguments.
  172.     'orb_id' the unique identifier of the ORB implementation. This MUST be
  173.              the same string as the 'constant' CORBA.ORB_ID.
  174.  
  175.     """
  176.     # The ORB id MUST be the same string as the 'constant' ORB_ID.
  177.     if orb_id != ORB_ID:
  178.         raise INITIALIZE() # System exception.
  179.  
  180.     # The ORB is a singleton (ie. there can only be one ORB instance per
  181.     # process (have I made this point clear yet?!?).
  182.     ORB.__lk.acquire()
  183.     try:
  184.         if ORB.__instance is not None:
  185.         raise ORB.__instance
  186.  
  187.         ORB.__instance = self
  188.  
  189.     finally:
  190.         ORB.__lk.release()
  191.  
  192.     # A list of pending DII requests.
  193.     self.__pending = []
  194.  
  195.     # The object adapter registered with the ORB.
  196.     self.__object_adapter = None
  197.  
  198.     # A mutex to make access to the ORB's data structures thread-safe.
  199.     self.__lk = fnorb_thread.allocate_lock()
  200.  
  201.     # ORB options can be specified via a configuration file, environment
  202.     # variables, or the command-line (in order of increasing precedence).
  203.     self.__options = self.__get_options(argv)
  204.  
  205.     # Initialise all GIOP transport protocols.
  206.     self.__protocols = self.__initialise_protocols()
  207.  
  208.     # A dictionary containing the names and references of the available
  209.     # object services. Note that (currently) we do not have to lock this
  210.     # dictionary as it only written to in *this* constructor.  All other
  211.     # accesses are read-only.
  212.     self.__services = {} # {Identifier : ObjectReference}
  213.  
  214.     # Initialise the available object services.
  215.     #
  216.     # The only two reserved COS ids are 'InterfaceRepository' and 
  217.     # 'NameService' so these are the only two services that we attempt
  218.     # to initialise (it is assumed that, given a naming service,
  219.     # application objects can find any other required services/objects).
  220.     #
  221.     # Naming service.
  222.     ns = self.__initialise_naming_service()
  223.      if ns is not None:
  224.          self.__services['NameService'] = ns
  225.  
  226.      # Interface repository.
  227.       ir = self.__initialise_interface_repository()
  228.       if ir is not None:
  229.           self.__services['InterfaceRepository'] = ir
  230.  
  231.     return
  232.  
  233.     #########################################################################
  234.     # CORBA ORB interface.
  235.     #########################################################################
  236.  
  237.     def object_to_string(self, object):
  238.     """ Create a stringified object reference. """
  239.  
  240.     if object is not None:
  241.         # Get the IOR from the object reference.
  242.         ior = object._fnorb_ior()
  243.  
  244.     else:
  245.         # Create an IOR with no profiles.
  246.         ior = IOP.IOR()
  247.  
  248.     # Stringify it!
  249.     return ior._fnorb_to_string()
  250.  
  251.     def string_to_object(self, stringified_ior):
  252.     """ Convert a stringified object reference into a live object!
  253.     
  254.     Note that this call does NOT attempt to connect to the remote object
  255.     and it will succeed even if the object reference is 'stale' i.e even if
  256.     the remote object no longer exists.
  257.  
  258.     """
  259.     # This contains a subtle Fnorb-ism as it allows for UOL's in the
  260.     # string!
  261.     return self.__resolve_uol(stringified_ior)
  262.  
  263.     def list_initial_services(self):
  264.     """ List the names of the available object services. """
  265.  
  266.     # Only return the names of the services that are 'up and running'!
  267.     up_and_running = []
  268.     for identifier in self.__services.keys():
  269.         # Get the service's object reference.
  270.         service = self.__services[identifier]
  271.  
  272.          # To find out if the object reference is still valid we have to
  273.          # invoke an operation on it. The '_is_a' operation is pretty
  274.         # harmless, so we do that!
  275.          try:
  276.         # We don't care about the result!
  277.          service._is_a('IDL:omg.org/CORBA/Object:1.0')
  278.  
  279.         # The call succeeded, so add the name of the service to the
  280.         # list.
  281.         up_and_running.append(identifier)
  282.  
  283.          except SystemException:
  284.         pass
  285.  
  286.     return up_and_running
  287.  
  288.     def resolve_initial_references(self, identifier):
  289.     """ Return a reference to the object service named by 'identifier'. """
  290.  
  291.     try:
  292.         service = self.__services[identifier]
  293.  
  294.          # To find out if the object reference is still valid we have to
  295.          # invoke an operation on it. The '_is_a' operation is pretty
  296.         # harmless, so we do that!
  297.         #
  298.         # We don't care about the result!
  299.         service._is_a('IDL:omg.org/CORBA/Object:1.0')
  300.  
  301.     # We get a 'KeyError' if a service with the name 'identifier' is
  302.     # not present, and a 'SystemException' if the service's object
  303.     # reference is 'stale'.
  304.     except (KeyError, SystemException):
  305.         raise ORB.InvalidName()
  306.  
  307.     return service
  308.  
  309.     def nil(self):
  310.     """ Generate a NIL object reference. """
  311.  
  312.     return None
  313.  
  314.     #########################################################################
  315.     # CORBA TypeCode factory interface.
  316.     #########################################################################
  317.     
  318.     def create_struct_tc(self, id, name, members):
  319.     return StructTypeCode(id, name, members)
  320.  
  321.     def create_union_tc(self, id, name, discriminator_type, members):
  322.     return UnionTypeCode(id, name, discriminator_type, members)
  323.  
  324.     def create_enum_tc(self, id, name, members):
  325.     return EnumTypeCode(id, name, members)
  326.  
  327.     def create_alias_tc(self, id, name, original_type):
  328.     return AliasTypeCode(id, name, original_type)
  329.  
  330.     def create_exception_tc(self, id, name, members):
  331.     return ExceptionTypeCode(id, name, members)
  332.  
  333.     def create_interface_tc(self, id, name):
  334.     return InterfaceTypeCode(id, name)
  335.  
  336.     def create_string_tc(self, bound):
  337.     return StringTypeCode(bound)
  338.  
  339.     def create_wstring_tc(self, bound):
  340.     return WstringTypeCode(bound)
  341.  
  342.     def create_fixed_tc(self, digits, scale):
  343.     return FixedTypeCode(digits, scale)
  344.     
  345.     def create_sequence_tc(self, bound, element_type):
  346.     return SequenceTypeCode(bound, element_type)
  347.  
  348.     def create_recursive_sequence_tc(self, bound, offset):
  349.     return RecursiveSequenceTypeCode(bound, offset)
  350.  
  351.     def create_array_tc(self, length, element_type):
  352.     return ArrayTypeCode(length, element_type)
  353.  
  354.     #########################################################################
  355.     # CORBA DII interface.
  356.     #########################################################################
  357.  
  358.     def send_multiple_requests(self, requests):
  359.     """ Send multiple requests. """
  360.  
  361.     # Add the requests to our list of those pending.
  362.     #
  363.     # fixme: If the client never actually gets the replies, this list will
  364.     # grow and grow!!
  365.     self.__lk.acquire()
  366.     self.__pending = self.__pending + requests
  367.     self.__lk.release()
  368.  
  369.     # Send each request.
  370.     for request in requests:
  371.         request.send()
  372.  
  373.     return
  374.  
  375.     def send_multiple_requests_oneway(self, requests):
  376.     """ Send multiple requests as 'oneway' operations. """
  377.  
  378.     # Send each request 'oneway'.
  379.     for request in requests:
  380.         request.send_oneway()
  381.  
  382.     return
  383.  
  384.     def poll_next_response(self):
  385.     """ Return true if there is at least one response waiting. """
  386.  
  387.     self.__lk.acquire()
  388.     for request in self.__pending:
  389.         if request.poll_response():
  390.         result = 1
  391.         break
  392.  
  393.     else:
  394.         result = 0
  395.     self.__lk.release()
  396.  
  397.     return result
  398.  
  399.     def get_next_response(self):
  400.     """ Get the next DII response. """
  401.  
  402.     self.__lk.acquire()
  403.     got_response = 0
  404.     while not got_response:
  405.         for i in range(len(self.__pending)):
  406.         if self.__pending[i].poll_response():
  407.             result = self.__pending[i]
  408.             got_response = 1
  409.             break
  410.  
  411.     # Delete the request from the pending queue.
  412.     del self.__pending[i]
  413.  
  414.     self.__lk.release()
  415.     return result
  416.  
  417.     #########################################################################
  418.     # Fnorb-specific interface.
  419.     #########################################################################
  420.  
  421.     def _fnorb_register_object_adapter(self, object_adapter):
  422.     """ Register an Object Adapter. """
  423.  
  424.     self.__object_adapter = object_adapter
  425.     return
  426.  
  427.     def _fnorb_object_adapter(self):
  428.     """ Return the object adapter. """
  429.  
  430.     return self.__object_adapter
  431.  
  432.     def _fnorb_threading_model(self):
  433.     """ Return the threading model being used by the ORB. """
  434.  
  435.     self.__lk.acquire()
  436.     if self.__options['Threading Model'] == 'Threaded':
  437.         threading_model = Util.THREADED
  438.  
  439.     else:
  440.         threading_model = Util.REACTIVE
  441.     self.__lk.release()
  442.  
  443.     return threading_model
  444.  
  445.     def _fnorb_thread_pool_size(self):
  446.     """ Return the size of the thread pool. """
  447.  
  448.     self.__lk.acquire()
  449.     thread_pool_size = eval(self.__options['Thread Pool Size'])
  450.     self.__lk.release()
  451.  
  452.     return thread_pool_size
  453.  
  454.     def _fnorb_protocols(self):
  455.     """ Return the list of the GIOP transport protocols. """
  456.  
  457.     # Return a copy of the list so that it cannot be modified!
  458.     return self.__protocols[:]
  459.  
  460.     def _fnorb_register_type(self, old, new):
  461.     """ Register a new type. """
  462.  
  463.     # Get a reference to the Type Manager.
  464.     tm = TypeManager.TypeManager_init()
  465.  
  466.     # Get the Interface Repository id of the old type.
  467.     ifr_id = tm.get_ifr_id(old)
  468.  
  469.     # Get the typecode constant of the old type
  470.     typecode_constant = tm.get_typecode_constant(ifr_id)
  471.  
  472.     # Register the new type.
  473.     tm.add_type(ifr_id, typecode_constant, new)
  474.  
  475.     return
  476.  
  477.     # This method is used by the BOA and the TypeCode modules.
  478.     def _fnorb_ior_to_object(self, ior):
  479.     """ Convert an IOR instance into a live object! """
  480.  
  481.     # If the IOR has an empty list of profiles then it is a NIL object
  482.     # reference!
  483.     if len(ior.profiles) == 0:
  484.         object = None
  485.  
  486.     else:
  487.         # If the IOR references an object in *this* ORB, then we create
  488.         # a 'local' object reference.  Local object references are more
  489.         # efficient as they bypass the usual marshalling and unmarshalling
  490.         # stages of operation invocations.
  491.         if self.__is_local_object(ior):
  492.         object = LocalObject(ior)
  493.  
  494.         # Otherwise, the IOR references a 'remote' object.
  495.         else:
  496.         # Get a reference to the type manager.
  497.         tm = TypeManager.TypeManager_init()
  498.  
  499.         # Find the Python stub class that implements the interface.
  500.         klass = tm.get_python_object(ior.type_id)
  501.         
  502.         # If the Python class was found then create an instance of it!
  503.         if klass is not None:
  504.             object = apply(klass, (ior,))
  505.  
  506.         # Otherwise, we create an instance of the generic type,
  507.         # 'CORBA.Object'.  Operations can still be invoked on the
  508.         # object via the DII.
  509.         #
  510.         # This is used extensively in applications such as the Naming
  511.         # Service where IOR's must be sent and received without the
  512.         # application having access to the stubs.
  513.         else:
  514.             object = Object(ior)
  515.  
  516.     return object
  517.  
  518.     def _fnorb_override_options(self, options):
  519.     """ Override ORB options. """
  520.     
  521.     self.__lk.acquire()
  522.     self.__options.update(options)
  523.     options = self.__options.copy()
  524.     self.__lk.release()
  525.  
  526.     return options
  527.  
  528.     def _fnorb_options(self):
  529.     """ Return the ORB options in a dictionary. """
  530.  
  531.     self.__lk.acquire()
  532.     options = self.__options.copy()
  533.     self.__lk.release()
  534.  
  535.     return options
  536.  
  537.     #########################################################################
  538.     # Private interface.
  539.     #########################################################################
  540.  
  541.     def __get_options(self, argv):
  542.     """ Get any ORB options.
  543.  
  544.     ORB options can be specified via a configuration file, environment
  545.     variables, or the command-line (in order of increasing precedence).
  546.  
  547.     """
  548.     # Start with a dictionary of required default options.
  549.     options = {'Threading Model': 'Reactive', 'Thread Pool Size': '10'}
  550.  
  551.     # Get any options specified on the command line.
  552.     command_line = self.__get_command_line_options(argv)
  553.  
  554.     # Get any options specified via environment variables.
  555.     environment = self.__get_environment_options()
  556.  
  557.     # Does the command line contain the name of a configuration file?
  558.     if command_line.has_key('ConfigFile'):
  559.         # Read the options from the configuration file.
  560.         config_file = self.__get_config_options(command_line['ConfigFile'])
  561.  
  562.     # How about the environment?
  563.     elif environment.has_key('ConfigFile'):
  564.         # Read the options from the configuration file.
  565.         config_file = self.__get_config_options(environment['ConfigFile'])
  566.  
  567.     # Otherwise, there is no configuration file.
  568.     else:
  569.         config_file = {}
  570.  
  571.     # Now lets put them all together, starting with least precedence.
  572.     options.update(config_file)
  573.     options.update(environment)
  574.     options.update(command_line)
  575.  
  576.     return options
  577.  
  578.     def __get_command_line_options(self, argv):
  579.     """ Get any options specified on the command line. """
  580.  
  581.     # Work on a copy of the command line arguments.
  582.     args = argv[:]
  583.     
  584.     # Command line arguments used by the ORB are stripped from the list.
  585.     # We accomplish this by first emptying the list and then putting back
  586.     # any non-ORB arguments!
  587.     #
  588.     # Empty the list without the destroying the list object itself.
  589.     del argv[:]
  590.  
  591.     # For convenience we return any ORB options in a dictionary.
  592.     options = {}
  593.  
  594.     i = 0
  595.     while i < len(args):
  596.         arg = args[i]
  597.  
  598.         if regex.match('--ORBconfig-file=.*', arg) != -1:
  599.         value = arg[string.find(arg, '=') + 1:]
  600.         options['ConfigFile'] = value
  601.  
  602.         elif regex.match('--ORBinterface-repository=.*', arg) != -1:
  603.         value = arg[string.find(arg, '=') + 1:]
  604.         options['Interface Repository'] = value
  605.  
  606.         elif regex.match('--ORBnaming-service=.*', arg) != -1:
  607.         value = arg[string.find(arg, '=') + 1:]
  608.         options['Naming Service'] = value
  609.  
  610.         elif regex.match('--ORBthreading-model=.*', arg) != -1:
  611.         value = arg[string.find(arg, '=') + 1:]
  612.         options['Threading Model'] = value
  613.  
  614.         elif regex.match('--ORBthread-pool-size=.*', arg) != -1:
  615.         value = arg[string.find(arg, '=') + 1:]
  616.         options['Thread Pool Size'] = value
  617.  
  618.         else:
  619.         argv.append(arg)
  620.  
  621.         i = i + 1
  622.  
  623.     return options
  624.  
  625.     def __get_environment_options(self):
  626.     """ Get any options specified via environment variables. """
  627.  
  628.     options = {}
  629.  
  630.     if os.environ.has_key('FNORB_CONFIG_FILE'):
  631.         options['ConfigFile'] = os.environ['FNORB_CONFIG_FILE']
  632.  
  633.     if os.environ.has_key('FNORB_INTERFACE_REPOSITORY'):
  634.         options['Interface Repository'] = os.environ['FNORB_INTERFACE_REPOSITORY']
  635.     if os.environ.has_key('FNORB_NAMING_SERVICE'):
  636.         options['Naming Service'] = os.environ['FNORB_NAMING_SERVICE']
  637.  
  638.     if os.environ.has_key('FNORB_THREADING_MODEL'):
  639.         options['Threading Model'] = os.environ['FNORB_THREADING_MODEL']
  640.  
  641.     if os.environ.has_key('FNORB_THREAD_POOL_SIZE'):
  642.         options['Thread Pool Size'] = os.environ['FNORB_THREAD_POOL_SIZE']
  643.  
  644.     return options
  645.  
  646.     def __get_config_options(self, filename):
  647.     """ Get any options specified via a configuration file. """
  648.  
  649.     options = {}
  650.     try:
  651.         # Read the configuration file as lines of text.
  652.         lines = open(filename).readlines()
  653.  
  654.         for line in lines:
  655.         # If the line starts with a hash ('#') then it is a comment.
  656.         if line[0] != '#':
  657.             # Find the position of the first colon (':').
  658.             colon = string.find(line, ':')
  659.  
  660.             # If there is no colon then just ignore the line.
  661.             if colon != -1:
  662.             # Get the key and value.
  663.             key = string.strip(line[:colon])
  664.             value = string.strip(line[colon+1:])
  665.  
  666.             # Add them to the dictionary.
  667.             options[key] = value
  668.  
  669.     # We get an IOError if the file doesn't exist or is not readable!
  670.     except IOError:
  671.         pass
  672.  
  673.     return options
  674.  
  675.     def __initialise_protocols(self):
  676.     """ Initialise the GIOP transport protocols. """
  677.  
  678.     # fixme: Currently only IIOP!
  679.     modules = ['IIOPProtocol']
  680.  
  681.     protocols = []
  682.     for protocol in modules:
  683.         try:
  684.         # Import the module.
  685.         exec('from Fnorb.orb import %s' % protocol)
  686.  
  687.         # Find the class that implements the protocol (derived from the
  688.         # base class 'Protocol.'Protocol').
  689.         klass = eval('%s.%s' % (protocol, protocol))
  690.  
  691.         # Add the protocol to the list of protocols available to the
  692.         # ORB.
  693.         protocols.append(apply(klass, ()))
  694.  
  695.         # If anything goes wrong with the import then just ignore the
  696.         # protocol.
  697.         except:
  698.         pass
  699.  
  700.     # If there are no protocols then we can't do much!
  701.     assert(len(protocols) > 0)
  702.  
  703.     return protocols
  704.  
  705.     def __initialise_interface_repository(self):
  706.     """ Initialise the interface repository! """
  707.  
  708.     # Get the UOL for the interface repository.
  709.     if self.__options.has_key('Interface Repository'):
  710.         # Resolve the UOL to create an active object reference for the
  711.         # interface repository.
  712.         ir = self.__resolve_uol(self.__options['Interface Repository'])
  713.  
  714.     # No UOL for the interface repository 8^(
  715.     else:
  716.         # If there's no UOL then there sure as hell ain't no interface
  717.         # repository!
  718.         ir = None
  719.  
  720.     return ir
  721.  
  722.     def __initialise_naming_service(self):
  723.     """ Initialise the naming service! """
  724.  
  725.     # fixme: We do the import here to get around the old circular import
  726.     # problems!
  727.     from Fnorb.cos.naming import CosNaming
  728.  
  729.     # Get the UOL for the naming service.
  730.     if self.__options.has_key('Naming Service'):
  731.         # Resolve the UOL to create an active object reference for the
  732.         # naming service.
  733.         ns = self.__resolve_uol(self.__options['Naming Service'], 1)
  734.  
  735.     # No UOL for the naming service 8^(
  736.     else:
  737.         # If there's no UOL then there sure as hell ain't no naming
  738.         # service!
  739.         ns = None
  740.  
  741.     return ns
  742.  
  743.     def __resolve_uol(self, uol, bootstrap=0):
  744.     """ Resolve a UOL to produce a 'live' object reference.
  745.  
  746.     UOL's can currently be either:-
  747.     
  748.     1) 'file:/the/pathname/of/a/file/containing/a/UOL'
  749.     2) 'IOR:a stringified object reference'
  750.     3) 'http://a/URL/pointing/to/a/text/document/containing/a/UOL'
  751.     4) 'name:/a/path/through/the/naming/service'
  752.  
  753.     Naming service names are not allowed if this is a 'boostrap' UOL (ie.
  754.     if we are resolving the UOL of the naming service!).
  755.  
  756.     """
  757.     # Stringified IOR.
  758.     if string.lower(uol[:4]) == 'ior:':
  759.         # Convert the stringified IOR into an IOR instance.
  760.         ior = new.instance(IOP.IOR, {})
  761.         ior._fnorb_from_string(uol)
  762.  
  763.         # Create an object reference from the IOR.
  764.         #
  765.         # Note that the call to '_fnorb_ior_to_object' does not attempt to
  766.         # connect to the remote object,  and it will succeed even if the
  767.         # object reference is 'stale' i.e even if the remote object no
  768.         # longer exists.
  769.         object = self._fnorb_ior_to_object(ior)
  770.  
  771.     # Filename.
  772.     elif string.lower(uol[:5]) == 'file:':
  773.         try:
  774.         file = open(uol[5:])
  775.         uol = string.strip(file.read())
  776.         file.close()
  777.  
  778.         # Recursively resolve the UOL.
  779.         object = self.__resolve_uol(uol, bootstrap)
  780.  
  781.         # We get an IOError if the file doesn't exist or is not readable!
  782.         except IOError:
  783.         object = None
  784.  
  785.     # URL.
  786.     elif string.lower(uol[:5]) == 'http:':
  787.         # Do the import here 'cos I'm not sure how much this will actually
  788.         # be used.
  789.         import urllib
  790.         try:
  791.         file = urllib.urlopen(uol)
  792.         uol = string.strip(file.read())
  793.         file.close()
  794.  
  795.         # Recursively resolve the UOL.
  796.         object = self.__resolve_uol(uol, bootstrap)
  797.  
  798.         except:
  799.         object = None
  800.  
  801.     # Naming service name.
  802.     elif string.lower(uol[:5]) == 'name:' and not bootstrap:
  803.         # Get a reference to the initial naming service context.
  804.         ctx = self.resolve_initial_references("NameService")
  805.  
  806.         # Create a naming service name from the string representation.
  807.         #
  808.         # fixme: This only works for names that contain components that
  809.         # do not use the 'kind' field (let's face it the 'kind' field
  810.         # was a crap idea anyway ;^)
  811.         #
  812.         # fixme: This should now be implemented as per the extended naming
  813.         # service specification.
  814.         name = Util._fnorb_string_to_name(uol)
  815.         
  816.         # Lookup the name.
  817.         object = ctx.resolve(name)
  818.  
  819.     else:
  820.         object = None
  821.  
  822.     return object
  823.  
  824.     def __is_local_object(self, ior):
  825.     """ Does the IOR reference an object in *this* ORB? """
  826.  
  827.     # Does the ORB have an object adapter initialised? (ie. are there any
  828.     # servants in this process?).
  829.     #
  830.     # fixme: Multiple object adapters?
  831.     if self.__object_adapter is not None:
  832.         # If so then we ask each protocol to examine the IOR and see if
  833.         # they think that the servant is in this process.
  834.         for protocol in self.__protocols:
  835.         if protocol.is_local(ior):
  836.             result = 1
  837.             break
  838.  
  839.         else:
  840.         result = 0
  841.  
  842.     # If there is no object adaptor then there sure as hell ain't no
  843.     # servants!
  844.     else:
  845.         result = 0
  846.         
  847.     return result
  848.  
  849.  
  850. class Object:
  851.     """ CORBA Object References (implementation of the Object interface). """
  852.  
  853.     # Repository id attribute.
  854.     _FNORB_ID = 'IDL:omg.org/CORBA/Object:1.0'
  855.  
  856.     def __init__(self, ior):
  857.     """ Constructor.
  858.  
  859.     'ior' is the IOR used to construct the object reference.
  860.  
  861.     """
  862.     self._ior = ior
  863.  
  864.     # If the IOR has an empty list of profiles then it is a NIL object
  865.     # reference!
  866.     if len(ior.profiles) == 0:
  867.         self.__is_nil = 1
  868.  
  869.     else:
  870.         # We can only use the object if it lives in an ORB that supports
  871.         # IIOP!  If the object reference does NOT contain an IIOP profile,
  872.         # then this call will raise an 'INV_OBJREF' exception.
  873.         self.__iiop_profile = ior._fnorb_iiop_profile()
  874.  
  875.         # Get a reference to the GIOP Client Manager.
  876.         gcm = GIOPClientManager.GIOPClientManager_init()
  877.  
  878.         # Get a GIOP client that is connected to the remote object.
  879.         self.__client = gcm.get_client(ior)
  880.         self.__is_nil = 0
  881.  
  882.     # The following flag indicates whether or not we have received a
  883.     # 'LOCATION_FORWARD' reply from the remote object.
  884.     self.__forwarded = 0
  885.  
  886.     # Mutex to make access to the object reference thread-safe (this is a
  887.     # 'protected' attribute as it is used by the derived class
  888.     # 'LocalObject').
  889.     self._lk = fnorb_thread.allocate_lock()
  890.  
  891.     return
  892.  
  893.     def __del__(self):
  894.     """ Destructor. """
  895.     
  896.     if not self.__is_nil:
  897.         # Get a reference to the GIOP Client Manager.
  898.         gcm = GIOPClientManager.GIOPClientManager_init()
  899.  
  900.         # Let the Connection Manager know that we have finished with the
  901.         # GIOP client (GIOP clients are reference counted by the
  902.         # Connection Manager so that they can be cleaned up when
  903.         # necessary).
  904.         gcm.delete_client(self._ior)
  905.  
  906.     return
  907.  
  908.     #########################################################################
  909.     # Client-side CORBA Object interface.
  910.     #########################################################################
  911.  
  912.     def _is_nil(self):
  913.     """ True if the object reference is nil, otherwise false.
  914.  
  915.     A Nil object reference contains an empty set of profiles!
  916.  
  917.     """
  918.     return self.__is_nil
  919.  
  920.     def _hash(self):
  921.     """ Return a hash value for the object reference. """
  922.  
  923.     self._lk.acquire()
  924.     if self.__is_nil:
  925.         hash_value = hash(None)
  926.  
  927.     else:
  928.         hash_value = abs(hash(self._ior))
  929.     self._lk.release()
  930.  
  931.     return hash_value
  932.  
  933.     def _create_request(self, operation, inputs, outputs, exceptions, **kw):
  934.     """ Create a DII Request. """
  935.  
  936.     return apply(Request,
  937.              (self, operation, inputs, outputs, exceptions), kw)
  938.  
  939.     def _narrow(self, klass):
  940.     """ Narrow the object reference to the specified interface type. """
  941.  
  942.     # fixme: This assumes the interface stub is loaded. Not a bad
  943.     # assumption!
  944.     if self._is_a(klass._FNORB_ID):
  945.         # Create a new IOR containing the specified interface type.
  946.         self._lk.acquire()
  947.         result = klass(IOP.IOR(klass._FNORB_ID, self._ior.profiles))
  948.         self._lk.release()
  949.  
  950.     else:
  951.         result = None
  952.  
  953.     return result
  954.         
  955.     #########################################################################
  956.     # Server-side CORBA Object interface.
  957.     #########################################################################
  958.  
  959.     def _is_a(self, *args, **kw):
  960.         """ Operation: IDL:omg.org/CORBA/Object/is_a:1.0 """
  961.  
  962.         # Typecodes for 'in' and 'inout' parameters.
  963.         inputs = [CORBA.TC_string]
  964.  
  965.         # Typecodes for the result, 'inout' and 'out' parameters.
  966.         outputs = [CORBA.TC_boolean]
  967.  
  968.         # Create a request object.
  969.         request = self._create_request("_is_a", inputs, outputs, [])
  970.  
  971.         # Make the request!
  972.         apply(request.invoke, args, kw)
  973.  
  974.         # Return the results.
  975.         return request.results()
  976.  
  977.     def _non_existent(self, *args, **kw):
  978.         """ Operation: IDL:omg.org/CORBA/Object/non_existent:1.0 """
  979.  
  980.         # Typecodes for the result, 'inout' and 'out' parameters.
  981.         outputs = [CORBA.TC_boolean]
  982.  
  983.         # Create a request object.
  984.         request = self._create_request("_non_existent", [], outputs, [])
  985.  
  986.         # Make the request!
  987.         apply(request.invoke, args, kw)
  988.  
  989.         # Return the results.
  990.         return request.results()
  991.  
  992.     def _interface(self, *args, **kw):
  993.         """ Operation: IDL:omg.org/CORBA/Object/_interface:1.0 """
  994.  
  995.         # Typecodes for the result, 'inout' and 'out' parameters.
  996.         outputs = [CORBA.typecode("IDL:omg.org/CORBA/InterfaceDef:1.0")]
  997.  
  998.         # Create a request object.
  999.         request = self._create_request("_interface", [], outputs, [])
  1000.  
  1001.         # Make the request!
  1002.         apply(request.invoke, args, kw)
  1003.  
  1004.         # Return the results.
  1005.         return request.results()
  1006.  
  1007.     #########################################################################
  1008.     # Non-CORBA interface.
  1009.     #########################################################################
  1010.  
  1011.     def _fnorb_ior(self):
  1012.     """ Return the IOR of the object reference. """
  1013.  
  1014.     self._lk.acquire()
  1015.     ior = self._ior
  1016.     self._lk.release()
  1017.  
  1018.     return ior
  1019.  
  1020.     def _fnorb_client(self):
  1021.     """ Return the IIOP client that is connected to the remote object. """
  1022.  
  1023.     self._lk.acquire()
  1024.     client = self.__client
  1025.     self._lk.release()
  1026.  
  1027.     return client
  1028.  
  1029.     def _fnorb_forwarded(self):
  1030.     """ Have we received a 'LOCATION_FORWARD' reply? """
  1031.  
  1032.     self._lk.acquire()
  1033.     forwarded = self.__forwarded
  1034.     self._lk.release()
  1035.  
  1036.     return forwarded
  1037.  
  1038.     def _fnorb_forward(self, ior):
  1039.     """ 'Forward' the object reference to the specified IOR. """
  1040.  
  1041.     self._lk.acquire()
  1042.     self.__forwarded = 1
  1043.  
  1044.     # Get a reference to the GIOP Client Manager.
  1045.     gcm = GIOPClientManager.GIOPClientManager_init()
  1046.  
  1047.     # Get a GIOP client that is connected to the forwarded address.
  1048.     self.__client = gcm.get_client(ior)
  1049.     self._lk.release()
  1050.  
  1051.     return
  1052.  
  1053.     def _fnorb_unforward(self):
  1054.     """ 'Unforward' the object back to its original IOR!
  1055.  
  1056.     This method is called if the connection to the forwarded object fails.
  1057.  
  1058.     """
  1059.     self._lk.acquire()
  1060.     self.__forwarded = 0
  1061.  
  1062.     # Get a reference to the GIOP Client Manager.
  1063.     gcm = GIOPClientManager.GIOPClientManager_init()
  1064.  
  1065.     # Get a GIOP client that is connected to the original address.
  1066.     self.__client = gcm.get_client(self._ior)
  1067.     self._lk.release()
  1068.  
  1069.     return
  1070.  
  1071.     def _fnorb_marshal(self, cursor):
  1072.     """ Marshal the object reference onto an octet stream. """
  1073.  
  1074.     self._ior._fnorb_marshal(cursor)
  1075.     return
  1076.  
  1077.     #########################################################################
  1078.     # Convenience methods for getting at the object's IIOP profile!
  1079.     #########################################################################
  1080.  
  1081.     def _fnorb_iiop_profile(self):
  1082.     """ Return the IIOP profile from the object's IOR.
  1083.  
  1084.     This is a convenience/performance function to save DII routines
  1085.     having to scan the IOR every time.
  1086.  
  1087.     """
  1088.     # A NIL object reference doesn't even have any profiles!
  1089.     if self.__is_nil:
  1090.         raise INV_OBJREF() # System exception.
  1091.  
  1092.     return self.__iiop_profile
  1093.  
  1094.     def _fnorb_host(self):
  1095.     """ Return the hostname contained in the object's IIOP profile. """
  1096.  
  1097.     # A NIL object reference doesn't even have any profiles!
  1098.     if self.__is_nil:
  1099.         raise INV_OBJREF() # System exception.
  1100.  
  1101.     return self.__iiop_profile.host
  1102.  
  1103.     def _fnorb_port(self):
  1104.     """ Return the port number contained in the object's IIOP profile. """
  1105.  
  1106.     # A NIL object reference doesn't even have any profiles!
  1107.     if self.__is_nil:
  1108.         raise INV_OBJREF() # System exception.
  1109.  
  1110.     return self.__iiop_profile.port
  1111.  
  1112.     def _fnorb_object_key(self):
  1113.     """ Return the object key contained in the object's IIOP profile. """
  1114.  
  1115.     # A NIL object reference doesn't even have any profiles!
  1116.     if self.__is_nil:
  1117.         raise INV_OBJREF() # System exception.
  1118.  
  1119.     return self.__iiop_profile.object_key
  1120.  
  1121.  
  1122. class LocalObject(Object):
  1123.     """ CORBA Object References for local objects (ie. in *this* ORB). """
  1124.  
  1125.     def __init__(self, ior):
  1126.     """ Constructor.
  1127.  
  1128.     'ior' is the IOR used to construct the object reference.
  1129.  
  1130.     """
  1131.     self._ior = ior
  1132.  
  1133.     # Set the '_FNORB_ID' as for stub classes.
  1134.     self._FNORB_ID = self._ior.type_id
  1135.  
  1136.     # We can only use the object if it lives in an ORB that supports IIOP!
  1137.     # If the object reference does NOT contain an IIOP profile, then this
  1138.     # call will raise an 'INV_OBJREF' exception.
  1139.     self._iiop_profile = ior._fnorb_iiop_profile()
  1140.  
  1141.     # Local object references CANNOT be nil!
  1142.     self.__is_nil = 0
  1143.  
  1144.     # Mutex to make access to the object reference thread-safe.
  1145.     #
  1146.     # This is a 'protected' attribute as it is used by methods in the
  1147.     # base class 'Object'.
  1148.     self._lk = fnorb_thread.allocate_lock()
  1149.  
  1150.     return
  1151.  
  1152.     def __del__(self):
  1153.     """ Destructor.
  1154.  
  1155.     Override the destructor in the base class.
  1156.  
  1157.     """
  1158.     pass
  1159.  
  1160.     def __getattr__(self, name):
  1161.     """ Pass method invocations onto the local implementation. """
  1162.  
  1163.     # Get a reference to the BOA.
  1164.     boa = BOA.BOA_init()
  1165.     
  1166.     # Lookup the implementation.
  1167.     impl = boa._fnorb_get_implementation(self._iiop_profile.object_key)
  1168.  
  1169.     # Lookup the attribute on the implementation.
  1170.     return getattr(impl, name)
  1171.  
  1172.     #########################################################################
  1173.     # Client-side CORBA Object interface.
  1174.     #########################################################################
  1175.  
  1176.     def _create_request(self, operation, inputs, outputs, exceptions, **kw):
  1177.      """ Create a local DII Request. """
  1178.  
  1179.      return apply(LocalRequest,
  1180.               (self, operation, inputs, outputs, exceptions), kw)
  1181.  
  1182.     #########################################################################
  1183.     # Server-side CORBA interface.
  1184.     #########################################################################
  1185.  
  1186.     def _is_a(self, logical_type_id):
  1187.     """ Return true if the object reference is of the specified type. """
  1188.  
  1189.     # Get a reference to the BOA.
  1190.     boa = BOA.BOA_init()
  1191.     
  1192.     # Lookup the implementation.
  1193.     impl = boa._fnorb_get_implementation(self._iiop_profile.object_key)
  1194.  
  1195.     return self.__is_a(impl.__class__, logical_type_id)
  1196.  
  1197.     def _non_existent(self):
  1198.     """ Return true if the object has been destroyed. """
  1199.  
  1200.     # Get a reference to the BOA.
  1201.     boa = BOA.BOA_init()
  1202.     
  1203.     return not boa._fnorb_object_here(self._iiop_profile.object_key)
  1204.  
  1205.     def _interface(self):
  1206.     """ Return the repository object that defines the interface.
  1207.  
  1208.     The ORB must have access to an Interface Repository for this method
  1209.     to succeed.
  1210.  
  1211.     """
  1212.     # Get a reference to the BOA.
  1213.     boa = BOA.BOA_init()
  1214.     
  1215.     # Lookup the implementation.
  1216.     impl = boa._fnorb_get_implementation(self._iiop_profile.object_key)
  1217.  
  1218.     # Get a reference to the ORB that we are living in.
  1219.     orb = ORB_init()
  1220.  
  1221.     # Get a reference to the Interface Repository.
  1222.     ir = orb.resolve_initial_references('InterfaceRepository')
  1223.  
  1224.     # Lookup our interface id to get the interface definition object.
  1225.     return ir.lookup_id(impl._FNORB_ID)
  1226.  
  1227.     #########################################################################
  1228.     # Private interface.
  1229.     #########################################################################
  1230.  
  1231.     def __is_a(self, klass, logical_type_id):
  1232.     """ Return true if the class is an implementation of the type. """
  1233.  
  1234.     if klass._FNORB_ID == logical_type_id:
  1235.         result = 1
  1236.  
  1237.     else:
  1238.         for base in klass.__bases__:
  1239.         if self.__is_a(base, logical_type_id):
  1240.             result = 1
  1241.             break
  1242.  
  1243.         else:
  1244.         result = 0
  1245.  
  1246.     return result
  1247.  
  1248.  
  1249. class Object_skel:
  1250.     """ CORBA Object Skeletons. """
  1251.  
  1252.     # Repository id attribute.
  1253.     _FNORB_ID = 'IDL:omg.org/CORBA/Object:1.0'
  1254.  
  1255.     def __init__(self):
  1256.       """ Constructor.
  1257.  
  1258.     Normally, skeleton implementations are not required to call this
  1259.     constructor as initialisation is forced via '__getattr__'. However, if
  1260.     the implementation overrides '__getattr__' it must call this
  1261.     constructor as part of its own initialisation.
  1262.  
  1263.     """
  1264.  
  1265.       self.__initialise()
  1266.       return
  1267.  
  1268.     def __getattr__(self, name):
  1269.      """ Trap the first attribute access to force initialisation! """
  1270.  
  1271.     # Force initialisation.
  1272.     #
  1273.     # fixme: Is this thread-safe - I think not!!!!!!!!!!
  1274.      if not self.__dict__.has_key('_initialised'):
  1275.          self.__initialise()
  1276.  
  1277.     # Provide the usual 'getattr' semantics!
  1278.      if not self.__dict__.has_key(name):
  1279.          raise AttributeError, name
  1280.  
  1281.      return self.__dict__[name]
  1282.  
  1283.     #########################################################################
  1284.     # Client-side CORBA Object interface.
  1285.     #########################################################################
  1286.  
  1287.     def _is_nil(self):
  1288.     """ True if the object reference is nil, otherwise false.
  1289.  
  1290.     Implementations are never nil!
  1291.  
  1292.     """
  1293.     return 0
  1294.  
  1295.     #########################################################################
  1296.     # Server-side CORBA interface.
  1297.     #########################################################################
  1298.  
  1299.     def _is_a(self, logical_type_id):
  1300.     """ Return true if the object reference is of the specified type. """
  1301.  
  1302.     return self.__is_a(self.__class__, logical_type_id)
  1303.  
  1304.     def _interface(self):
  1305.     """ Return the repository object that defines the interface.
  1306.  
  1307.     The ORB must have access to an Interface Repository for this method
  1308.     to succeed.
  1309.  
  1310.     """
  1311.     # Get a reference to the ORB that we are living in.
  1312.     orb = ORB_init()
  1313.  
  1314.     # Get a reference to the Interface Repository.
  1315.     ir = orb.resolve_initial_references('InterfaceRepository')
  1316.  
  1317.     # Lookup our interface id to get the interface definition object.
  1318.     return ir.lookup_id(self._FNORB_ID)
  1319.  
  1320.     #########################################################################
  1321.     # Skeleton methods for the server-side CORBA interface.
  1322.     #########################################################################
  1323.  
  1324.     def _skel__is_a(self, server_request):
  1325.         """ Operation: IDL:omg.org/CORBA/Object/_is_a:1.0 """
  1326.  
  1327.         # Typecodes for 'in' and 'inout' parameters.
  1328.         inputs = [CORBA.TC_string]
  1329.  
  1330.         # Typecodes for the result, 'inout' and 'out' parameters.
  1331.         outputs = [CORBA.TC_boolean]
  1332.  
  1333.         # Initialise the server request object.
  1334.         server_request.initialise(inputs, outputs, [])
  1335.  
  1336.         # Unmarshal the arguments to the request.
  1337.         arguments = server_request.arguments()
  1338.  
  1339.         # Invoke the implementation.
  1340.         results = apply(self._is_a, arguments)
  1341.  
  1342.         # Create the reply.
  1343.         server_request.results(results)
  1344.  
  1345.         return
  1346.  
  1347.     def _skel__interface(self, server_request):
  1348.         """ Operation: IDL:omg.org/CORBA/Object/_interface:1.0 """
  1349.  
  1350.         # Typecodes for the result, 'inout' and 'out' parameters.
  1351.         outputs = [CORBA.typecode("IDL:omg.org/CORBA/InterfaceDef:1.0")]
  1352.  
  1353.         # Initialise the server request object.
  1354.         server_request.initialise([], outputs, [])
  1355.  
  1356.         # Invoke the implementation.
  1357.         results = apply(self._interface, ())
  1358.  
  1359.         # Create the reply.
  1360.         server_request.results(results)
  1361.  
  1362.         return
  1363.  
  1364.     #########################################################################
  1365.     # Fnorb-specific interface.
  1366.     #########################################################################
  1367.  
  1368.     def _fnorb_ior(self):
  1369.      """ Return the IOR for the current thread. """
  1370.  
  1371.     # Get the object key appropriate for the current thread.
  1372.     object_key = self._fnorb_object_key()
  1373.  
  1374.     # Create an IOR using the object key and the object's interface
  1375.     # repository id.
  1376.     boa = BOA.BOA_init()
  1377.     ior = boa._fnorb_create_ior(object_key, self._FNORB_ID)
  1378.  
  1379.      return ior
  1380.  
  1381.     def _fnorb_object_key(self):
  1382.     """ Return the object key for the current thread. """
  1383.  
  1384.     # Get the object key appropriate for the current thread.
  1385.     self.__lk.acquire()
  1386.     try:
  1387.         object_key = self.__object_keys[fnorb_thread.get_ident()]
  1388.  
  1389.     # fixme: Should we pick *any* of our object keys here?
  1390.     except KeyError:
  1391.         raise "No object key for this thread!"
  1392.     self.__lk.release()
  1393.  
  1394.     return object_key
  1395.  
  1396.     def _fnorb_add_object_key(self, object_key):
  1397.     """ Add the object key to our key table. """
  1398.  
  1399.     self.__lk.acquire()
  1400.     self.__object_keys[fnorb_thread.get_ident()] = object_key
  1401.     self.__lk.release()
  1402.  
  1403.     return
  1404.  
  1405.     def _fnorb_delete_object_key(self):
  1406.     """ Delete the object key for the current thread. """
  1407.  
  1408.     self.__lk.acquire()
  1409.     try:
  1410.         del self.__object_keys[fnorb_thread.get_ident()]
  1411.  
  1412.     except KeyError:
  1413.         pass
  1414.     self.__lk.release()
  1415.  
  1416.     return
  1417.  
  1418.     def _fnorb_marshal(self, cursor):
  1419.     """ Marshal the object reference onto an octet stream. """
  1420.     
  1421.     # Create the appropriate IOR for the current calling context.
  1422.     ior = self._fnorb_ior()
  1423.  
  1424.     # Marshal the IOR onto the octet stream.
  1425.     ior._fnorb_marshal(cursor)
  1426.  
  1427.     return
  1428.  
  1429.     #########################################################################
  1430.     # Private interface.
  1431.     #########################################################################
  1432.  
  1433.     def __initialise(self):
  1434.     """ (Pseudo) Constructor! """
  1435.  
  1436.     # A single implementation instance can be referred to by many
  1437.     # different object references (ie. by many different object keys).
  1438.     # Therefore, to determine the object key for any individual operation
  1439.     # invocation, we store each object key in a dictionary keyed on
  1440.     # thread id. In non-threaded environments, there will obviously only
  1441.     # be at most one entry in the dictionary.
  1442.     self.__object_keys = {} # {ThreadId: ObjectKey}
  1443.  
  1444.     # A mutex to make access to the object key dictionary thread-safe.
  1445.     self.__lk = fnorb_thread.allocate_lock()
  1446.  
  1447.     # A flag to indicate that we have been initialised!
  1448.     self._initialised = 1
  1449.  
  1450.     return
  1451.  
  1452.     def __is_a(self, klass, logical_type_id):
  1453.     """ Return true if the class is an implementation of the type. """
  1454.  
  1455.     # We check for the existence of the '_FNORB_ID' attribute first to
  1456.     # allow implementations to multiply inherit from classes that are
  1457.     # nothing to do with Fnorb.
  1458.     if hasattr(klass, '_FNORB_ID') and klass._FNORB_ID == logical_type_id:
  1459.         result = 1
  1460.  
  1461.     else:
  1462.         for base in klass.__bases__:
  1463.         if self.__is_a(base, logical_type_id):
  1464.             result = 1
  1465.             break
  1466.  
  1467.         else:
  1468.         result = 0
  1469.  
  1470.     return result
  1471.  
  1472.  
  1473. # Standard/built-in modules.
  1474. import new, os, regex, string
  1475.  
  1476. # Fnorb modules.
  1477. import BOA, GIOPClientManager, IOP, TypeManager
  1478.  
  1479. # The following modules are defined in the spec. as being part of the CORBA
  1480. # module.
  1481. from   DII                 import *
  1482. from   DSI                 import *
  1483. from   TypeCode            import *
  1484.  
  1485. # The following modules also defined in the spec. as being part of the CORBA
  1486. # module, but they rely on definitions in the TypeCode module.
  1487. from   Any                 import *
  1488. from   InterfaceRepository import *
  1489.  
  1490. #############################################################################
  1491.