#!/usr/bin/env python ############################################################################# # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999 # All Rights Reserved. # # The software contained on this media is the property of the DSTC Pty # Ltd. Use of this software is strictly in accordance with the # license agreement in the accompanying LICENSE.HTML file. If your # distribution of this software does not contain a LICENSE.HTML file # then you have no rights to use this software in any manner and # should contact DSTC at the address below to determine an appropriate # licensing arrangement. # # DSTC Pty Ltd # Level 7, GP South # Staff House Road # University of Queensland # St Lucia, 4072 # Australia # Tel: +61 7 3365 4310 # Fax: +61 7 3365 4311 # Email: enquiries@dstc.edu.au # # This software is being provided "AS IS" without warranty of any # kind. In no event shall DSTC Pty Ltd be liable for damage of any # kind arising out of or in connection with the use or performance of # this software. # # Project: Fnorb # File: $Source: /cvsroot/fnorb/fnorb/cos/naming/NamingContext.py,v $ # Version: @(#)$RCSfile: NamingContext.py,v $ $Revision: 1.11 $ # ############################################################################# """ COS Naming Service Naming Contexts. """ # Standard/built-in modules. import string # Fnorb modules. from Fnorb.orb import fnorb_thread, uuid, BOA, CORBA # Stubs and skeletons. import CosNaming, CosNaming_skel # Naming service modules. import BindingIterator def NamingContextFactory_init(): """ Initialise the Naming Contect Factory. This is a factory function for the NamingContextFactory class (the factory is a singleton (ie. there can only be one instance per process)). """ try: ncf = NamingContextFactory() except NamingContextFactory, ncf: pass return ncf class NamingContextFactory: """ A factory for naming contexts! The factory is a singleton (ie. there can only be one instance per process). """ # Singleton instance. __instance = None def __init__(self): """ Constructor. """ # The factory is a singleton (ie. there can only be one instance per # process). if NamingContextFactory.__instance is not None: raise NamingContextFactory.__instance NamingContextFactory.__instance = self return def create_naming_context(self, object_key=None): """ Create and return a new naming context. """ # Create an object key for the context. if object_key is None: # Generate a unique object key for the context. object_key = uuid.uuid() # Create an instance of the implementation class. impl = NamingContext() # Create an object reference. boa = BOA.BOA_init() nc = boa.create(object_key, NamingContext._FNORB_ID) # Activate the implementation (ie. connect the generated object # reference to the implementation). boa.obj_is_ready(nc, impl) return impl class NamingContext(CosNaming_skel.NamingContext_skel): """ Naming context implementation. """ # A binding iterator factory that is shared by every context instance. bif = BindingIterator.BindingIteratorFactory_init() def __init__(self, nc_factory=None, d_bindings=None): """ Constructor. """ # A factory responsible for creating new naming contexts. if nc_factory is None: self.__nc_factory = NamingContextFactory_init() else: self.__nc_factory = nc_factory # A dictionary containing the bindings in the context, in the form:- # {(NameComponentId, NameComponentKind): (Binding, StringifiedIOR)}. # # We cannot key the dictionary directly on a NameComponent instance # because the NameComponent class is generated automatically by the # IDL compiler and therefore has no '__hash__' method. if d_bindings is None: self.__d_bindings = {} else: self.__d_bindings = d_bindings # A mutex to make access to the binding dictionary safe in threaded # environments. self.__lk = fnorb_thread.allocate_lock() return ######################################################################### # CORBA interface. ######################################################################### def bind(self, n, obj): """ Bind the name 'n' to the object reference obj. """ # An 'empty' name is invalid. if len(n) == 0: raise CosNaming.NamingContext.InvalidName() # Get the first component of the name. component = n[0] # The binding dictionary is keyed on (ComponentId, ComponentKind). key = str((component.id, component.kind)) # If there is exactly one component in the name then the operation # takes place in *this* context. if len(n) == 1: self.__lk.acquire() try: # Is the component already bound? if self.__d_bindings.has_key(key): raise CosNaming.NamingContext.AlreadyBound() # Create the binding. binding = CosNaming.Binding(n, CosNaming.nobject) # Stringify the object reference. orb = CORBA.ORB_init() stringified_ior = orb.object_to_string(obj) # Add it to the binding dictionary. self.__d_bindings[key] = (binding, stringified_ior) finally: self.__lk.release() # Otherwise, attempt to continue resolution into the next context. else: self.__resolve('bind', key, n, obj) return def rebind(self, n, obj): """ Rebind the name 'n' to the object reference obj. """ # An 'empty' name is invalid. if len(n) == 0: raise CosNaming.NamingContext.InvalidName() # Get the first component of the name. component = n[0] # The binding dictionary is keyed on (ComponentId, ComponentKind). key = str((component.id, component.kind)) # If there is exactly one component in the name then the operation # takes place in *this* context. if len(n) == 1: # Create the binding. binding = CosNaming.Binding(n, CosNaming.nobject) # Stringify the object reference. orb = CORBA.ORB_init() stringified_ior = orb.object_to_string(obj) # Add it to the binding dictionary. self.__lk.acquire() self.__d_bindings[key] = (binding, stringified_ior) self.__lk.release() # Otherwise, attempt to continue resolution into the next context. else: self.__resolve('rebind', key, n, obj) return def bind_context(self, n, nc): """ Bind the name 'n' to the naming context nc. """ # An 'empty' name is invalid. if len(n) == 0: raise CosNaming.NamingContext.InvalidName() # Get the first component of the name. component = n[0] # The binding dictionary is keyed on (ComponentId, ComponentKind). key = str((component.id, component.kind)) # If there is exactly one component in the name then the operation # takes place in *this* context. if len(n) == 1: self.__lk.acquire() try: # Is the component already bound? if self.__d_bindings.has_key(key): raise CosNaming.NamingContext.AlreadyBound() # Create the binding. binding = CosNaming.Binding(n, CosNaming.ncontext) # Stringify the object reference. orb = CORBA.ORB_init() stringified_ior = orb.object_to_string(nc) # Add it to the binding dictionary. self.__d_bindings[key] = (binding, stringified_ior) finally: self.__lk.release() # Otherwise, attempt to continue resolution into the next context. else: self.__resolve('bind_context', key, n, nc) return def rebind_context(self, n, nc): """ Rebind the name 'n' to the naming context nc. """ # An 'empty' name is invalid. if len(n) == 0: raise CosNaming.NamingContext.InvalidName() # Get the first component of the name. component = n[0] # The binding dictionary is keyed on (ComponentId, ComponentKind). key = str((component.id, component.kind)) # If there is exactly one component in the name then the operation # takes place in *this* context. if len(n) == 1: # Create the binding. binding = CosNaming.Binding(n, CosNaming.ncontext) # Stringify the object reference. orb = CORBA.ORB_init() stringified_ior = orb.object_to_string(nc) # Add it to the binding dictionary. self.__lk.acquire() self.__d_bindings[key] = (binding, stringified_ior) self.__lk.release() # Otherwise, attempt to continue resolution into the next context. else: self.__resolve('rebind_context', key, n, nc) return def resolve(self, n): """ Resolve the name 'n'. """ # An 'empty' name is invalid. if len(n) == 0: raise CosNaming.NamingContext.InvalidName() # Get the first component of the name. component = n[0] # The binding dictionary is keyed on (ComponentId, ComponentKind). key = str((component.id, component.kind)) # If there is exactly one component in the name then the operation # takes place in *this* context. if len(n) == 1: self.__lk.acquire() try: # Is the component bound in this context? if not self.__d_bindings.has_key(key): raise CosNaming.NamingContext.NotFound \ (CosNaming.NamingContext.missing_node, n) # Get the stringified IOR bound to the component. (binding, stringified_ior) = self.__d_bindings[key] # Convert the stringified IOR into an active object reference. orb = CORBA.ORB_init() result = orb.string_to_object(stringified_ior) finally: self.__lk.release() # Otherwise, attempt to continue resolution into the next context. else: result = self.__resolve('resolve', key, n) return result def unbind(self, n): """ Unbind the name 'n'. """ # An 'empty' name is invalid. if len(n) == 0: raise CosNaming.NamingContext.InvalidName() # Get the first component of the name. component = n[0] # The binding dictionary is keyed on (ComponentId, ComponentKind). key = str((component.id, component.kind)) # If there is exactly one component in the name then the operation # takes place in *this* context. if len(n) == 1: self.__lk.acquire() try: # Is the component bound in this context? if not self.__d_bindings.has_key(key): raise CosNaming.NamingContext.NotFound \ (CosNaming.NamingContext.missing_node, n) # Delete the binding. del self.__d_bindings[key] finally: self.__lk.release() # Otherwise, attempt to continue resolution into the next context. else: self.__resolve('unbind', key, n) return def new_context(self): """ Create a new naming context. """ # Ask the factory to create a new naming context for us. return self.__nc_factory.create_naming_context() def bind_new_context(self, n): """ Create a new naming context and bind it to the name 'n'. """ # An 'empty' name is invalid. if len(n) == 0: raise CosNaming.NamingContext.InvalidName() # Get the first component of the name. component = n[0] # The binding dictionary is keyed on (ComponentId, ComponentKind). key = str((component.id, component.kind)) # If there is exactly one component in the name then the operation # takes place in *this* context. if len(n) == 1: self.__lk.acquire() try: # Is the component already bound? if self.__d_bindings.has_key(key): raise CosNaming.NamingContext.AlreadyBound() # Create the binding. binding = CosNaming.Binding(n, CosNaming.ncontext) # Create a new context. nc = self.new_context() # Stringify the object reference. orb = CORBA.ORB_init() stringified_ior = orb.object_to_string(nc) # Add it to the binding dictionary. self.__d_bindings[key] = (binding, stringified_ior) finally: self.__lk.release() # Otherwise, attempt to continue resolution into the next context. else: nc = self.__resolve('bind_new_context', key, n) return nc def destroy(self): """ Destroy the naming context. """ self.__lk.acquire() try: # Naming contexts must be empty to be destroyed! if len(self.__d_bindings.keys()) > 0: raise CosNaming.NamingContext.NotEmpty() finally: self.__lk.release() # Unregister myself from the BOA. boa = BOA.BOA_init() boa.deactivate_obj(self) return def list(self, how_many): """ List the bindings in a context. """ # Create a list of the bindings in the context. # # Note that we do not use 'self.__d_bindings.values()' to get at the # dictionary contents; this is a small concession to allow Python # shelves to be used for creating persistent contexts (shelves do not # implement the 'values' method). self.__lk.acquire() bl = [] for key in self.__d_bindings.keys(): (binding, obj) = self.__d_bindings[key] bl.append(binding) self.__lk.release() # If there are more bindings than have been requested, then return a # binding iterator. if len(bl) > how_many: iterator = NamingContext.bif.create_binding_iterator(bl[how_many:]) # Otherwise return a nil reference for the iterator. else: ## orb = CORBA.ORB_init() ## iterator = orb.nil() iterator = None return (bl[:how_many], iterator) ######################################################################### # Internal interface. ######################################################################### def __resolve(self, op, key, n, *args): """ Resolve a naming operation through a naming graph. """ self.__lk.acquire() try: # If the component is not bound in this context then we can go no # further! if not self.__d_bindings.has_key(key): raise CosNaming.NamingContext.NotFound \ (CosNaming.NamingContext.missing_node, n) # Get the binding! (binding, stringified_ior) = self.__d_bindings[key] finally: self.__lk.release() # If the binding contains another naming context then continue the # resolution. if binding.binding_type == CosNaming.ncontext: # Convert the stringified IOR into an active object reference. orb = CORBA.ORB_init() next = orb.string_to_object(stringified_ior) # Find the appropriate method on the context. method = getattr(next, op) # Invoke the method translating CORBA system exceptions into # 'CannotProceed' exceptions. try: result = apply(method, (n[1:],) + args) except CORBA.SystemException: raise CosNaming.NamingContext.CannotProceed(self, n) # Otherwise, the binding contains some other object reference and # therefore we cannot continue the resolution. else: raise CosNaming.NamingContext.NotFound \ (CosNaming.NamingContext.not_context, n) return result #############################################################################