#!/usr/bin/env python ############################################################################# # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999, 2000 # 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/CORBA.py,v $ # Version: @(#)$RCSfile: CORBA.py,v $ $Revision: 1.54 $ # ############################################################################# """ CORBA module. """ # Fnorb modules. import fnorb_thread, TypeManager, Util from Fnorb.orb import CONV_FRAME # ORB identifier. ORB_ID = 'The ORB called Fnorb v1.1.Return.of.Fnorb' # Boolean 'constants' as specified in the Python language mapping. TRUE = 1 FALSE = 0 ############################################################################# # Exception classes. ############################################################################# # Exception base class. class CORBAException: pass # User exceptions. class UserException(CORBAException): pass # System exceptions. # # Enum: IDL:omg.org/CORBA/completion_status:1.0 COMPLETED_YES = Util.EnumMember('COMPLETED_YES', 0) COMPLETED_NO = Util.EnumMember('COMPLETED_NO', 1) COMPLETED_MAYBE = Util.EnumMember('COMPLETED_MAYBE', 2) completion_status = Util.Enum("IDL:omg.org/CORBA/completion_status:1.0", [COMPLETED_YES, COMPLETED_NO, COMPLETED_MAYBE]) TypeManager.TypeManager_init().add_type("IDL:omg.org/CORBA/completion_status:1.0", "000000000000001100000088000000000000002849444C3A6F6D672E6F72672F434F5242412F636F6D706C6574696F6E5F7374617475733A312E300000000012636F6D706C6574696F6E5F737461747573000000000000030000000E434F4D504C455445445F5945530000000000000D434F4D504C455445445F4E4F0000000000000010434F4D504C455445445F4D4159424500", completion_status) class SystemException(CORBAException): """ Struct: IDL:omg.org/CORBA/SystemException:1.0 """ _FNORB_ID = "IDL:omg.org/CORBA/SystemException:1.0" def __init__(self, _minor=0, _completed=COMPLETED_NO): """ Constructor. """ self.minor = _minor self.completed = _completed return def __getinitargs__(self): """ Return the constructor arguments for unpickling. """ return (self.minor, self.completed) def __str__(self): """ Return a string representation of the exception. """ return 'Minor: ' + `self.minor` + ' Completed: ' + str(self.completed) # fixme: Replace these methods with typecode marshalling? def _fnorb_marshal(self, cursor): """ Marshal the structure onto an octet stream. """ cursor.marshal('L', self.minor) cursor.marshal('L', self.completed.value()) return def _fnorb_unmarshal(self, cursor): """ Unmarshal the structure from an octet stream. """ self.minor = cursor.unmarshal('L') self.completed = completion_status[int(cursor.unmarshal('L'))] return # A class for every system exception! class UNKNOWN (SystemException): pass # The unknown exception! class BAD_PARAM (SystemException): pass # Invalid parameter was passed. class NO_MEMORY (SystemException): pass # Memory allocation failure. class IMP_LIMIT (SystemException): pass # Violated implementation limit. class COMM_FAILURE (SystemException): pass # Communication failure. class INV_OBJREF (SystemException): pass # Invalid object reference. class NO_PERMISSION (SystemException): pass # No permission for operation. class INTERNAL (SystemException): pass # ORB internal error. class MARSHAL (SystemException): pass # Error marshalling param/result. class INITIALIZE (SystemException): pass # ORB initialisation failure. class NO_IMPLEMENT (SystemException): pass # Op. implementation unavailable. class BAD_TYPECODE (SystemException): pass # Bad typecode. class BAD_OPERATION (SystemException): pass # Invalid operation. class NO_RESOURCES (SystemException): pass # Insufficient resources for req. class NO_RESPONSE (SystemException): pass # Response to req. not available. class PERSIST_STORE (SystemException): pass # Persistent storage failure. class BAD_INV_ORDER (SystemException): pass # Routine inv. out of order class TRANSIENT (SystemException): pass # Transient failure, reissue req. class FREE_MEM (SystemException): pass # Cannot free memory. class INV_IDENT (SystemException): pass # Invalid identifier syntax. class INV_FLAG (SystemException): pass # Invalid flag was specified. class INTF_REPOS (SystemException): pass # Error accessing I/F repository. class BAD_CONTEXT (SystemException): pass # Error processing context obj. class OBJ_ADAPTER (SystemException): pass # Failure detected by adapter. class DATA_CONVERSION (SystemException): pass # Data conversion error. class OBJECT_NOT_EXIST(SystemException): pass # Non-existent object, del OR. class TRANSACTION_REQUIRED (SystemException): pass class TRANSACTION_ROLLEDBACK (SystemException): pass class INVALID_TRANSACTION (SystemException): pass class INV_POLICY (SystemException): pass class CODESET_INCOMPATIBLE (SystemException): pass ############################################################################# # The ORB interface. ############################################################################# def ORB_init(argv=[], orb_id=ORB_ID): """ Initialise the ORB. This is a factory function for the ORB class (the ORB is a singleton (ie. there can only be one ORB instance per process)). """ try: orb = ORB(argv, orb_id) except ORB, orb: pass return orb def ORB_delete(): orb = ORB_init() for srv in orb._ORB__services.keys(): del orb._ORB__services[srv] orb.__class__._ORB__instance = None class ORB: """ The ORB object. The ORB is a singleton (ie. there can only be one ORB instance per process). """ # Singleton instance. __instance = None # Mutex to make access via the factory function thread-safe. __lk = fnorb_thread.allocate_lock() # Exceptions. class InvalidName(UserException): pass def __init__(self, argv, orb_id): """ Constructor. 'argv' command line arguments. 'orb_id' the unique identifier of the ORB implementation. This MUST be the same string as the 'constant' CORBA.ORB_ID. """ # The ORB id MUST be the same string as the 'constant' ORB_ID. if orb_id != ORB_ID: raise INITIALIZE() # System exception. # The ORB is a singleton (ie. there can only be one ORB instance per # process (have I made this point clear yet?!?). ORB.__lk.acquire() try: if ORB.__instance is not None: raise ORB.__instance ORB.__instance = self finally: ORB.__lk.release() # A list of pending DII requests. self.__pending = [] # The object adapter registered with the ORB. self.__object_adapter = None # A mutex to make access to the ORB's data structures thread-safe. self.__lk = fnorb_thread.allocate_lock() # The process codeset for this ORB, initialized on first access self.__process_codeset = None # ORB options can be specified via a configuration file, environment # variables, or the command-line (in order of increasing precedence). self.__options = self.__get_options(argv) # Initialise all GIOP transport protocols. self.__protocols = self.__initialise_protocols() # A dictionary containing the names and references of the available # object services. Note that (currently) we do not have to lock this # dictionary as it only written to in *this* constructor. All other # accesses are read-only. self.__services = {} # {Identifier : ObjectReference} # Initialise the available object services. # # The only two reserved COS ids are 'InterfaceRepository' and # 'NameService' so these are the only two services that we attempt # to initialise (it is assumed that, given a naming service, # application objects can find any other required services/objects). # # Naming service. ns = self.__initialise_naming_service() if ns is not None: self.__services['NameService'] = ns # Interface repository. ir = self.__initialise_interface_repository() if ir is not None: self.__services['InterfaceRepository'] = ir return ######################################################################### # CORBA ORB interface. ######################################################################### def object_to_string(self, object): """ Create a stringified object reference. """ if object is not None: # Get the IOR from the object reference. ior = object._fnorb_ior() else: # Create an IOR with no profiles. ior = IOP.IOR() # Stringify it! return ior._fnorb_to_string() def string_to_object(self, stringified_ior): """ Convert a stringified object reference into a live object! Note that this call does NOT attempt to connect to the remote object and it will succeed even if the object reference is 'stale' i.e even if the remote object no longer exists. """ # This contains a subtle Fnorb-ism as it allows for UOL's in the # string! return self.__resolve_uol(stringified_ior) def list_initial_services(self): """ List the names of the available object services. """ # Only return the names of the services that are 'up and running'! up_and_running = [] for identifier in self.__services.keys(): # Get the service's object reference. service = self.__services[identifier] # To find out if the object reference is still valid we have to # invoke an operation on it. The '_is_a' operation is pretty # harmless, so we do that! try: # We don't care about the result! service._is_a('IDL:omg.org/CORBA/Object:1.0') # The call succeeded, so add the name of the service to the # list. up_and_running.append(identifier) except SystemException: pass return up_and_running def resolve_initial_references(self, identifier): """ Return a reference to the object service named by 'identifier'. """ try: service = self.__services[identifier] # To find out if the object reference is still valid we have to # invoke an operation on it. The '_is_a' operation is pretty # harmless, so we do that! # # We don't care about the result! service._is_a('IDL:omg.org/CORBA/Object:1.0') # We get a 'KeyError' if a service with the name 'identifier' is # not present, and a 'SystemException' if the service's object # reference is 'stale'. except (KeyError, SystemException): raise ORB.InvalidName() return service def nil(self): """ Generate a NIL object reference. """ return None ######################################################################### # CORBA TypeCode factory interface. ######################################################################### def create_struct_tc(self, id, name, members): return StructTypeCode(id, name, members) def create_union_tc(self, id, name, discriminator_type, members): return UnionTypeCode(id, name, discriminator_type, members) def create_enum_tc(self, id, name, members): return EnumTypeCode(id, name, members) def create_alias_tc(self, id, name, original_type): return AliasTypeCode(id, name, original_type) def create_exception_tc(self, id, name, members): return ExceptionTypeCode(id, name, members) def create_interface_tc(self, id, name): return InterfaceTypeCode(id, name) def create_string_tc(self, bound): return StringTypeCode(bound) def create_wstring_tc(self, bound): return WstringTypeCode(bound) def create_fixed_tc(self, digits, scale): return FixedTypeCode(digits, scale) def create_sequence_tc(self, bound, element_type): return SequenceTypeCode(bound, element_type) def create_recursive_sequence_tc(self, bound, offset): return RecursiveSequenceTypeCode(bound, offset) def create_array_tc(self, length, element_type): return ArrayTypeCode(length, element_type) ######################################################################### # CORBA DII interface. ######################################################################### def send_multiple_requests(self, requests): """ Send multiple requests. """ # Add the requests to our list of those pending. # # fixme: If the client never actually gets the replies, this list will # grow and grow!! self.__lk.acquire() self.__pending = self.__pending + requests self.__lk.release() # Send each request. for request in requests: request.send() return def send_multiple_requests_oneway(self, requests): """ Send multiple requests as 'oneway' operations. """ # Send each request 'oneway'. for request in requests: request.send_oneway() return def poll_next_response(self): """ Return true if there is at least one response waiting. """ self.__lk.acquire() for request in self.__pending: if request.poll_response(): result = 1 break else: result = 0 self.__lk.release() return result def get_next_response(self): """ Get the next DII response. """ self.__lk.acquire() got_response = 0 while not got_response: for i in range(len(self.__pending)): if self.__pending[i].poll_response(): result = self.__pending[i] got_response = 1 break # Delete the request from the pending queue. del self.__pending[i] self.__lk.release() return result ######################################################################### # Fnorb-specific interface. ######################################################################### def _fnorb_register_object_adapter(self, object_adapter): """ Register an Object Adapter. """ self.__object_adapter = object_adapter return def _fnorb_object_adapter(self): """ Return the object adapter. """ return self.__object_adapter def _fnorb_threading_model(self): """ Return the threading model being used by the ORB. """ self.__lk.acquire() if self.__options['Threading Model'] == 'Threaded': threading_model = Util.THREADED else: threading_model = Util.REACTIVE self.__lk.release() return threading_model def _fnorb_thread_pool_size(self): """ Return the size of the thread pool. """ self.__lk.acquire() thread_pool_size = eval(self.__options['Thread Pool Size']) self.__lk.release() return thread_pool_size def _fnorb_protocols(self): """ Return the list of the GIOP transport protocols. """ # Return a copy of the list so that it cannot be modified! return self.__protocols[:] def _fnorb_register_type(self, old, new): """ Register a new type. """ # Get a reference to the Type Manager. tm = TypeManager.TypeManager_init() # Get the Interface Repository id of the old type. ifr_id = tm.get_ifr_id(old) # Get the typecode constant of the old type typecode_constant = tm.get_typecode_constant(ifr_id) # Register the new type. tm.add_type(ifr_id, typecode_constant, new) return # This method is used by the BOA and the TypeCode modules. def _fnorb_ior_to_object(self, ior): """ Convert an IOR instance into a live object! """ # If the IOR has an empty list of profiles then it is a NIL object # reference! if len(ior.profiles) == 0: object = None else: # If the IOR references an object in *this* ORB, then we create # a 'local' object reference. Local object references are more # efficient as they bypass the usual marshalling and unmarshalling # stages of operation invocations. if self.__is_local_object(ior): object = LocalObject(ior) # Otherwise, the IOR references a 'remote' object. else: # Get a reference to the type manager. tm = TypeManager.TypeManager_init() # Find the Python stub class that implements the interface. klass = tm.get_python_object(ior.type_id) # If the Python class was found then create an instance of it! if klass is not None: object = apply(klass, (ior,)) # Otherwise, we create an instance of the generic type, # 'CORBA.Object'. Operations can still be invoked on the # object via the DII. # # This is used extensively in applications such as the Naming # Service where IOR's must be sent and received without the # application having access to the stubs. else: object = Object(ior) return object def _fnorb_override_options(self, options): """ Override ORB options. """ self.__lk.acquire() self.__options.update(options) options = self.__options.copy() self.__lk.release() return options def _fnorb_options(self): """ Return the ORB options in a dictionary. """ self.__lk.acquire() options = self.__options.copy() self.__lk.release() return options def _fnorb_get_process_codeset(self): "Return the codeset used in narrow (byte) strings." if self.__process_codeset: return self.__process_codeset # There are two different ways to determine the process # code set in Python: using the locale, and using the default # encoding. We try the locale first, and fall back to the process # codeset if that fails import locale, Util, sys try: # On Unix, nl_langinfo(CODESET), if available, # returns the codeset codeset = locale.nl_langinfo(locale.CODESET) # convert codeset name to codeset number. Some systems # may return strange strings here, which might not be # known to codec2osf codeset = Util.codec2osf[codeset.lower()] self._fnorb_set_process_codeset(codeset) return codeset except: pass if sys.platform.startswith("win"): # On Windows, sys.getdefaultlocale returns the code page import _locale lang, codeset = _locale._getdefaultlocale() try: codeset = Util.codec2osf[codeset] self._fnorb_set_process_codeset(codeset) return codeset except: pass # fall back to system default encoding codeset = sys.getdefaultencoding() try: codeset = Util.codec2osf[codeset] self._fnorb_set_process_codeset(codeset) return codeset except: pass # fall back to ASCII codset = 0x00010020 self._fnorb_set_process_codeset(codeset) return codeset def _fnorb_set_process_codeset(self, codeset): "Set the process codeset for this ORB" self.__process_codeset = codeset ######################################################################### # Private interface. ######################################################################### def __get_options(self, argv): """ Get any ORB options. ORB options can be specified via a configuration file, environment variables, or the command-line (in order of increasing precedence). """ # Start with a dictionary of required default options. options = {'Threading Model': 'Reactive', 'Thread Pool Size': '10'} # Get any options specified on the command line. command_line = self.__get_command_line_options(argv) # Get any options specified via environment variables. environment = self.__get_environment_options() # Does the command line contain the name of a configuration file? if command_line.has_key('ConfigFile'): # Read the options from the configuration file. config_file = self.__get_config_options(command_line['ConfigFile']) # How about the environment? elif environment.has_key('ConfigFile'): # Read the options from the configuration file. config_file = self.__get_config_options(environment['ConfigFile']) # Otherwise, there is no configuration file. else: config_file = {} # Now lets put them all together, starting with least precedence. options.update(config_file) options.update(environment) options.update(command_line) return options def __get_command_line_options(self, argv): """ Get any options specified on the command line. """ # Work on a copy of the command line arguments. args = argv[:] # Command line arguments used by the ORB are stripped from the list. # We accomplish this by first emptying the list and then putting back # any non-ORB arguments! # # Empty the list without the destroying the list object itself. del argv[:] # For convenience we return any ORB options in a dictionary. options = {} i = 0 while i < len(args): arg = args[i] if re.match('--ORBconfig-file=.*', arg) != None: value = arg[string.find(arg, '=') + 1:] options['ConfigFile'] = value elif re.match('--ORBinterface-repository=.*', arg) != None: value = arg[string.find(arg, '=') + 1:] options['Interface Repository'] = value elif re.match('--ORBnaming-service=.*', arg) != None: value = arg[string.find(arg, '=') + 1:] options['Naming Service'] = value elif re.match('--ORBthreading-model=.*', arg) != None: value = arg[string.find(arg, '=') + 1:] options['Threading Model'] = value elif re.match('--ORBthread-pool-size=.*', arg) != None: value = arg[string.find(arg, '=') + 1:] options['Thread Pool Size'] = value else: argv.append(arg) i = i + 1 return options def __get_environment_options(self): """ Get any options specified via environment variables. """ options = {} if os.environ.has_key('FNORB_CONFIG_FILE'): options['ConfigFile'] = os.environ['FNORB_CONFIG_FILE'] if os.environ.has_key('FNORB_INTERFACE_REPOSITORY'): options['Interface Repository'] = os.environ['FNORB_INTERFACE_REPOSITORY'] if os.environ.has_key('FNORB_NAMING_SERVICE'): options['Naming Service'] = os.environ['FNORB_NAMING_SERVICE'] if os.environ.has_key('FNORB_THREADING_MODEL'): options['Threading Model'] = os.environ['FNORB_THREADING_MODEL'] if os.environ.has_key('FNORB_THREAD_POOL_SIZE'): options['Thread Pool Size'] = os.environ['FNORB_THREAD_POOL_SIZE'] return options def __get_config_options(self, filename): """ Get any options specified via a configuration file. """ options = {} try: # Read the configuration file as lines of text. lines = open(filename).readlines() for line in lines: # If the line starts with a hash ('#') then it is a comment. if line[0] != '#': # Find the position of the first colon (':'). colon = string.find(line, ':') # If there is no colon then just ignore the line. if colon != -1: # Get the key and value. key = string.strip(line[:colon]) value = string.strip(line[colon+1:]) # Add them to the dictionary. options[key] = value # We get an IOError if the file doesn't exist or is not readable! except IOError: pass return options def __initialise_protocols(self): """ Initialise the GIOP transport protocols. """ # fixme: Currently only IIOP! modules = ['IIOPProtocol'] protocols = [] for protocol in modules: try: # Import the module. exec('from Fnorb.orb import %s' % protocol) # Find the class that implements the protocol (derived from the # base class 'Protocol.'Protocol'). klass = eval('%s.%s' % (protocol, protocol)) # Add the protocol to the list of protocols available to the # ORB. protocols.append(apply(klass, ())) # If anything goes wrong with the import then just ignore the # protocol. except: pass # If there are no protocols then we can't do much! assert(len(protocols) > 0) return protocols def __initialise_interface_repository(self): """ Initialise the interface repository! """ # Get the UOL for the interface repository. if self.__options.has_key('Interface Repository'): # Resolve the UOL to create an active object reference for the # interface repository. ir = self.__resolve_uol(self.__options['Interface Repository']) # No UOL for the interface repository 8^( else: # If there's no UOL then there sure as hell ain't no interface # repository! ir = None return ir def __initialise_naming_service(self): """ Initialise the naming service! """ # fixme: We do the import here to get around the old circular import # problems! from Fnorb.cos.naming import CosNaming # Get the UOL for the naming service. if self.__options.has_key('Naming Service'): # Resolve the UOL to create an active object reference for the # naming service. ns = self.__resolve_uol(self.__options['Naming Service'], 1) # No UOL for the naming service 8^( else: # If there's no UOL then there sure as hell ain't no naming # service! ns = None return ns def __resolve_uol(self, uol, bootstrap=0): """ Resolve a UOL to produce a 'live' object reference. UOL's can currently be either:- 1) 'file:/the/pathname/of/a/file/containing/a/UOL' 2) 'IOR:a stringified object reference' 3) 'http://a/URL/pointing/to/a/text/document/containing/a/UOL' 4) 'name:/a/path/through/the/naming/service' Naming service names are not allowed if this is a 'boostrap' UOL (ie. if we are resolving the UOL of the naming service!). """ # Stringified IOR. if string.lower(uol[:4]) == 'ior:': # Convert the stringified IOR into an IOR instance. ior = new.instance(IOP.IOR, {}) ior._fnorb_from_string(uol) # Create an object reference from the IOR. # # Note that the call to '_fnorb_ior_to_object' does not attempt to # connect to the remote object, and it will succeed even if the # object reference is 'stale' i.e even if the remote object no # longer exists. object = self._fnorb_ior_to_object(ior) # Filename. elif string.lower(uol[:5]) == 'file:': try: file = open(uol[5:]) uol = string.strip(file.read()) file.close() # Recursively resolve the UOL. object = self.__resolve_uol(uol, bootstrap) # We get an IOError if the file doesn't exist or is not readable! except IOError: object = None # URL. elif string.lower(uol[:5]) == 'http:': # Do the import here 'cos I'm not sure how much this will actually # be used. import urllib try: file = urllib.urlopen(uol) uol = string.strip(file.read()) file.close() # Recursively resolve the UOL. object = self.__resolve_uol(uol, bootstrap) except: object = None # Naming service name. elif string.lower(uol[:5]) == 'name:' and not bootstrap: # Get a reference to the initial naming service context. ctx = self.resolve_initial_references("NameService") # Create a naming service name from the string representation. # This string representation is defined by the INS # (Interoperable Name Service) name = Util._fnorb_string_to_name(uol) # Lookup the name. object = ctx.resolve(name) elif uol.startswith('corbaloc:'): # From formal/02-05-15, section 13.6.10.1 # corbaloc:[iiop]:[version@]host[:port][/key] # corbaloc:rir:/key # There may be multiple comma-separated protocol/host/port tuples import IIOP # Split off key uol = uol.split('/',1) if len(uol) == 1: # No key uol = uol[0] key = None else: uol, key = uol # Traverse list of contact addresses objs = [] for obj_addr in uol[9:].split(','): if obj_addr == 'rir:': # resolve-initial-references IORs if key is None: key = 'NameService' try: objs.append(self.resolve_initial_references(key)) except ORB.InvalidName: pass continue if key is None: # XXX: Where is it specified that a missing # key means an empty string? key = '' # Everything else must be iiop if obj_addr.startswith('iiop:'): obj_addr = obj_addr[5:] elif obj_addr[0] == ':': obj_addr = obj_addr[1:] else: # Unsupported future protocol continue # Retrieve the version if obj_addr.find('@') != -1: version, obj_addr = obj_addr.split('@') major, minor = version.split('.') version = IIOP.Version(int(major), int(minor)) else: version = IIOP.Version(1, 0) # Split into host/port if obj_addr.find(':') != -1: host, port = obj_addr.split(':') port = int(port) else: host, port = obj_addr, 2809 # Build profile if version.major != 1: continue if version.minor == 0: profile = IIOP.ProfileBody_1_0(version, host, port, key) elif version in (1, 2): profile = IIOP.ProfileBody_1_1(version, host, port, key, []) else: continue profile = IOP.TaggedProfile(IOP.TAG_INTERNET_IOP, profile) # Build IOR ior = IOP.IOR('', [profile]) # Build Object objs.append(Object(ior)) # XXX: should send locate request # end obj_addr_list if objs: # XXX May consider other objects object = objs[0] else: object = None elif uol.startswith("corbaname:"): # From formal/02-05-15, section 13.6.10.1 # corbaname::555objs.com#a/string/path/to/obj first # resolves the NameService key, then resolves the path # within that NamingContext # Strip off corbaname: uol = uol[10:] # Split into corbaloc: data and INS data loc, path = uol.split('#') # Resolve the corbaloc data if loc.find('/') == -1: # Make sure there is an object key loc += '/NameService' ctx = self.__resolve_uol("corbaloc:" + loc) if ctx is not None: from Fnorb.cos.naming.CosNaming import NamingContext ctx = ctx._narrow(NamingContext) if ctx is not None: # Convert the INS data, without removing a name: prefix name = Util._fnorb_string_to_name(path, 0) try: # Lookup the name. object = ctx.resolve(name) except NamingContext.NotFound: object = None else: object = None return object def __is_local_object(self, ior): """ Does the IOR reference an object in *this* ORB? """ # Does the ORB have an object adapter initialised? (ie. are there any # servants in this process?). # # fixme: Multiple object adapters? if self.__object_adapter is not None: # If so then we ask each protocol to examine the IOR and see if # they think that the servant is in this process. for protocol in self.__protocols: if protocol.is_local(ior): result = 1 break else: result = 0 # If there is no object adaptor then there sure as hell ain't no # servants! else: result = 0 return result class Object: """ CORBA Object References (implementation of the Object interface). """ # Repository id attribute. _FNORB_ID = 'IDL:omg.org/CORBA/Object:1.0' def __init__(self, ior): """ Constructor. 'ior' is the IOR used to construct the object reference. """ self._ior = ior # If the IOR has an empty list of profiles then it is a NIL object # reference! if len(ior.profiles) == 0: self.__is_nil = 1 else: # We can only use the object if it lives in an ORB that supports # IIOP! If the object reference does NOT contain an IIOP profile, # then this call will raise an 'INV_OBJREF' exception. self.__iiop_profile = ior._fnorb_iiop_profile() # Get a reference to the GIOP Client Manager. gcm = GIOPClientManager.GIOPClientManager_init() # Get a GIOP client that is connected to the remote object. self.__client = gcm.get_client(ior) self.__is_nil = 0 # The following flag indicates whether or not we have received a # 'LOCATION_FORWARD' reply from the remote object. self.__forwarded = 0 # Mutex to make access to the object reference thread-safe (this is a # 'protected' attribute as it is used by the derived class # 'LocalObject'). self._lk = fnorb_thread.allocate_lock() # If the IOR contains code set info, we need to create a code # set context for p in ior.profiles: # IIOP profile if p.tag == IOP.TAG_INTERNET_IOP: major = p.profile_data.iiop_version.major minor = p.profile_data.iiop_version.minor if minor == 1 or minor == 2: for component in p.profile_data.components: if component.tag == IOP.TAG_CODE_SETS: comp_tc = CORBA.typecode( "IDL:omg.org/CONV_FRAME/CodeSetComponentInfo:1.0") encaps = OctetStream.Encapsulation(component.component_data) encaps_cursor = encaps.cursor() comp = comp_tc._fnorb_unmarshal_value(encaps_cursor) self.code_set_context = Util.negotiate_codeset(comp) return def __del__(self): """ Destructor. """ if not self.__is_nil: # Get a reference to the GIOP Client Manager. gcm = GIOPClientManager.GIOPClientManager_init() # Let the Connection Manager know that we have finished with the # GIOP client (GIOP clients are reference counted by the # Connection Manager so that they can be cleaned up when # necessary). gcm.delete_client(self._ior) return ######################################################################### # Client-side CORBA Object interface. ######################################################################### def _is_nil(self): """ True if the object reference is nil, otherwise false. A Nil object reference contains an empty set of profiles! """ return self.__is_nil def _hash(self): """ Return a hash value for the object reference. """ self._lk.acquire() if self.__is_nil: hash_value = hash(None) else: hash_value = abs(hash(self._ior)) self._lk.release() return hash_value def _create_request(self, operation, inputs, outputs, exceptions, **kw): """ Create a DII Request. """ # If we have determined a code set context, then use it if hasattr(self, 'code_set_context'): # Get the contexts keyword argument if kw.has_key('context'): contexts = kw['context'] else: contexts = [] kw['context'] = contexts # Add the code set context to the contexts contexts.append(self.code_set_context) return apply(Request, (self, operation, inputs, outputs, exceptions), kw) def _narrow(self, klass): """ Narrow the object reference to the specified interface type. """ # fixme: This assumes the interface stub is loaded. Not a bad # assumption! # checks self._ior.type_id before trying the (possibly remote) # _is_a(). Work around for interoperability with ORBs that do not # support _is_a(). if self._ior.type_id == klass._FNORB_ID or self._is_a(klass._FNORB_ID): # Create a new IOR containing the specified interface type. self._lk.acquire() result = klass(IOP.IOR(klass._FNORB_ID, self._ior.profiles)) self._lk.release() else: result = None return result ######################################################################### # Server-side CORBA Object interface. ######################################################################### def _is_a(self, *args, **kw): """ Operation: IDL:omg.org/CORBA/Object/is_a:1.0 """ # Typecodes for 'in' and 'inout' parameters. inputs = [CORBA.TC_string] # Typecodes for the result, 'inout' and 'out' parameters. outputs = [CORBA.TC_boolean] # Create a request object. request = self._create_request("_is_a", inputs, outputs, []) # Make the request! apply(request.invoke, args, kw) # Return the results. return request.results() def _non_existent(self, *args, **kw): """ Operation: IDL:omg.org/CORBA/Object/non_existent:1.0 """ # Typecodes for the result, 'inout' and 'out' parameters. outputs = [CORBA.TC_boolean] # Create a request object. request = self._create_request("_non_existent", [], outputs, []) # Make the request! apply(request.invoke, args, kw) # Return the results. return request.results() def _interface(self, *args, **kw): """ Operation: IDL:omg.org/CORBA/Object/_interface:1.0 """ # Typecodes for the result, 'inout' and 'out' parameters. outputs = [CORBA.typecode("IDL:omg.org/CORBA/InterfaceDef:1.0")] # Create a request object. request = self._create_request("_interface", [], outputs, []) # Make the request! apply(request.invoke, args, kw) # Return the results. return request.results() ######################################################################### # Non-CORBA interface. ######################################################################### def _fnorb_ior(self): """ Return the IOR of the object reference. """ self._lk.acquire() ior = self._ior self._lk.release() return ior def _fnorb_client(self): """ Return the IIOP client that is connected to the remote object. """ self._lk.acquire() client = self.__client self._lk.release() return client def _fnorb_forwarded(self): """ Have we received a 'LOCATION_FORWARD' reply? """ self._lk.acquire() forwarded = self.__forwarded self._lk.release() return forwarded def _fnorb_forward(self, ior): """ 'Forward' the object reference to the specified IOR. """ self._lk.acquire() self.__forwarded = 1 # Get a reference to the GIOP Client Manager. gcm = GIOPClientManager.GIOPClientManager_init() # Remove old client, update object gcm.delete_client(self._ior) self._ior = ior self.__iiop_profile = ior._fnorb_iiop_profile() # Get a GIOP client that is connected to the forwarded address. self.__client = gcm.get_client(ior) self._lk.release() return def _fnorb_unforward(self): """ 'Unforward' the object back to its original IOR! This method is called if the connection to the forwarded object fails. """ self._lk.acquire() self.__forwarded = 0 # Get a reference to the GIOP Client Manager. gcm = GIOPClientManager.GIOPClientManager_init() # Get a GIOP client that is connected to the original address. self.__client = gcm.get_client(self._ior) self._lk.release() return def _fnorb_marshal(self, cursor): """ Marshal the object reference onto an octet stream. """ self._ior._fnorb_marshal(cursor) return ######################################################################### # Convenience methods for getting at the object's IIOP profile! ######################################################################### def _fnorb_iiop_profile(self): """ Return the IIOP profile from the object's IOR. This is a convenience/performance function to save DII routines having to scan the IOR every time. """ # A NIL object reference doesn't even have any profiles! if self.__is_nil: raise INV_OBJREF() # System exception. return self.__iiop_profile def _fnorb_host(self): """ Return the hostname contained in the object's IIOP profile. """ # A NIL object reference doesn't even have any profiles! if self.__is_nil: raise INV_OBJREF() # System exception. return self.__iiop_profile.host def _fnorb_port(self): """ Return the port number contained in the object's IIOP profile. """ # A NIL object reference doesn't even have any profiles! if self.__is_nil: raise INV_OBJREF() # System exception. return self.__iiop_profile.port def _fnorb_object_key(self): """ Return the object key contained in the object's IIOP profile. """ # A NIL object reference doesn't even have any profiles! if self.__is_nil: raise INV_OBJREF() # System exception. return self.__iiop_profile.object_key class LocalObject(Object): """ CORBA Object References for local objects (ie. in *this* ORB). """ def __init__(self, ior): """ Constructor. 'ior' is the IOR used to construct the object reference. """ self._ior = ior # Set the '_FNORB_ID' as for stub classes. self._FNORB_ID = self._ior.type_id # We can only use the object if it lives in an ORB that supports IIOP! # If the object reference does NOT contain an IIOP profile, then this # call will raise an 'INV_OBJREF' exception. self._iiop_profile = ior._fnorb_iiop_profile() # Local object references CANNOT be nil! self.__is_nil = 0 # Mutex to make access to the object reference thread-safe. # # This is a 'protected' attribute as it is used by methods in the # base class 'Object'. self._lk = fnorb_thread.allocate_lock() return def __del__(self): """ Destructor. Override the destructor in the base class. """ pass def __getattr__(self, name): """ Pass method invocations onto the local implementation. """ # Get a reference to the BOA. boa = BOA.BOA_init() # Lookup the implementation. impl = boa._fnorb_get_implementation(self._iiop_profile.object_key) # Lookup the attribute on the implementation. return getattr(impl, name) ######################################################################### # Client-side CORBA Object interface. ######################################################################### def _create_request(self, operation, inputs, outputs, exceptions, **kw): """ Create a local DII Request. """ return apply(LocalRequest, (self, operation, inputs, outputs, exceptions), kw) ######################################################################### # Server-side CORBA interface. ######################################################################### def _is_a(self, logical_type_id): """ Return true if the object reference is of the specified type. """ # Get a reference to the BOA. boa = BOA.BOA_init() # Lookup the implementation. impl = boa._fnorb_get_implementation(self._iiop_profile.object_key) return self.__is_a(impl.__class__, logical_type_id) def _non_existent(self): """ Return true if the object has been destroyed. """ # Get a reference to the BOA. boa = BOA.BOA_init() return not boa._fnorb_object_here(self._iiop_profile.object_key) def _interface(self): """ Return the repository object that defines the interface. The ORB must have access to an Interface Repository for this method to succeed. """ # Get a reference to the BOA. boa = BOA.BOA_init() # Lookup the implementation. impl = boa._fnorb_get_implementation(self._iiop_profile.object_key) # Get a reference to the ORB that we are living in. orb = ORB_init() # Get a reference to the Interface Repository. ir = orb.resolve_initial_references('InterfaceRepository') # Lookup our interface id to get the interface definition object. return ir.lookup_id(impl._FNORB_ID) ######################################################################### # Private interface. ######################################################################### def __is_a(self, klass, logical_type_id): """ Return true if the class is an implementation of the type. """ if klass._FNORB_ID == logical_type_id: result = 1 else: for base in klass.__bases__: if self.__is_a(base, logical_type_id): result = 1 break else: result = 0 return result class Object_skel: """ CORBA Object Skeletons. """ # Repository id attribute. _FNORB_ID = 'IDL:omg.org/CORBA/Object:1.0' def __init__(self): """ Constructor. Normally, skeleton implementations are not required to call this constructor as initialisation is forced via '__getattr__'. However, if the implementation overrides '__getattr__' it must call this constructor as part of its own initialisation. """ self.__initialise() return def __getattr__(self, name): """ Trap the first attribute access to force initialisation! """ # Force initialisation. # # fixme: Is this thread-safe - I think not!!!!!!!!!! if not self.__dict__.has_key('_initialised'): self.__initialise() # Provide the usual 'getattr' semantics! if not self.__dict__.has_key(name): raise AttributeError, name return self.__dict__[name] ######################################################################### # Client-side CORBA Object interface. ######################################################################### def _is_nil(self): """ True if the object reference is nil, otherwise false. Implementations are never nil! """ return 0 ######################################################################### # Server-side CORBA interface. ######################################################################### def _is_a(self, logical_type_id): """ Return true if the object reference is of the specified type. """ return self.__is_a(self.__class__, logical_type_id) def _interface(self): """ Return the repository object that defines the interface. The ORB must have access to an Interface Repository for this method to succeed. """ # Get a reference to the ORB that we are living in. orb = ORB_init() # Get a reference to the Interface Repository. ir = orb.resolve_initial_references('InterfaceRepository') # Lookup our interface id to get the interface definition object. return ir.lookup_id(self._FNORB_ID) ######################################################################### # Skeleton methods for the server-side CORBA interface. ######################################################################### def _skel__is_a(self, server_request): """ Operation: IDL:omg.org/CORBA/Object/_is_a:1.0 """ # Typecodes for 'in' and 'inout' parameters. inputs = [CORBA.TC_string] # Typecodes for the result, 'inout' and 'out' parameters. outputs = [CORBA.TC_boolean] # Initialise the server request object. server_request.initialise(inputs, outputs, []) # Unmarshal the arguments to the request. arguments = server_request.arguments() # Invoke the implementation. results = apply(self._is_a, arguments) # Create the reply. server_request.results(results) return def _skel__interface(self, server_request): """ Operation: IDL:omg.org/CORBA/Object/_interface:1.0 """ # Typecodes for the result, 'inout' and 'out' parameters. outputs = [CORBA.typecode("IDL:omg.org/CORBA/InterfaceDef:1.0")] # Initialise the server request object. server_request.initialise([], outputs, []) # Invoke the implementation. results = apply(self._interface, ()) # Create the reply. server_request.results(results) return ######################################################################### # Fnorb-specific interface. ######################################################################### def _fnorb_ior(self): """ Return the IOR for the current thread. """ # Get the object key appropriate for the current thread. object_key = self._fnorb_object_key() # Create an IOR using the object key and the object's interface # repository id. boa = BOA.BOA_init() ior = boa._fnorb_create_ior(object_key, self._FNORB_ID) return ior def _fnorb_object_key(self): """ Return the object key for the current thread. """ # Get the object key appropriate for the current thread. self.__lk.acquire() try: try: object_key = self.__object_keys[fnorb_thread.get_ident()] # fixme: Should we pick *any* of our object keys here? except KeyError: raise "No object key for this thread!" return object_key finally: self.__lk.release() def _fnorb_add_object_key(self, object_key): """ Add the object key to our key table. """ self.__lk.acquire() self.__object_keys[fnorb_thread.get_ident()] = object_key self.__lk.release() return def _fnorb_delete_object_key(self): """ Delete the object key for the current thread. """ self.__lk.acquire() try: del self.__object_keys[fnorb_thread.get_ident()] except KeyError: pass self.__lk.release() return def _fnorb_marshal(self, cursor): """ Marshal the object reference onto an octet stream. """ # Create the appropriate IOR for the current calling context. ior = self._fnorb_ior() # Marshal the IOR onto the octet stream. ior._fnorb_marshal(cursor) return ######################################################################### # Private interface. ######################################################################### def __initialise(self): """ (Pseudo) Constructor! """ # A single implementation instance can be referred to by many # different object references (ie. by many different object keys). # Therefore, to determine the object key for any individual operation # invocation, we store each object key in a dictionary keyed on # thread id. In non-threaded environments, there will obviously only # be at most one entry in the dictionary. self.__object_keys = {} # {ThreadId: ObjectKey} # A mutex to make access to the object key dictionary thread-safe. self.__lk = fnorb_thread.allocate_lock() # A flag to indicate that we have been initialised! self._initialised = 1 return def __is_a(self, klass, logical_type_id): """ Return true if the class is an implementation of the type. """ # We check for the existence of the '_FNORB_ID' attribute first to # allow implementations to multiply inherit from classes that are # nothing to do with Fnorb. if hasattr(klass, '_FNORB_ID') and klass._FNORB_ID == logical_type_id: result = 1 else: for base in klass.__bases__: if self.__is_a(base, logical_type_id): result = 1 break else: result = 0 return result # Standard/built-in modules. import os, re, string # Python 1.5.1 and early didn't build new by default try: import new except ImportError: sys.stderr.write("Fnorb: failed to import 'new' module.\n\n") sys.stderr.write(" The new module is not built by default in Python 1.5.1 and\n") sys.stderr.write(" earlier. You should either upgrade to Python 1.5.2 (or later)\n") sys.stderr.write(" or compile the 'new' extension module.\n\n") sys.exit(1) # Fnorb modules. import BOA, GIOPClientManager, IOP, TypeManager # The following modules are defined in the spec. as being part of the CORBA # module. from DII import * from DSI import * from TypeCode import * from LongDouble import LongDouble as long_double from Fixed import Fixed as fixed # The following modules also defined in the spec. as being part of the CORBA # module, but they rely on definitions in the TypeCode module. from Any import * from InterfaceRepository import * #############################################################################