-------------------------------------------------------------------------------- ------------------------------ ##### ## ------------------------------ ------------------------------ ## ## # ## ------------------------------ ------------------------------ ## ## ## ## ------------------------------ ------------------------------ ## ## # ## ------------------------------ ------------------------------ ##### ### ###### ------------------------------ -------------------------------- -------------------------------- ----------------------- An Object Request Broker in Lua ------------------------ -------------------------------------------------------------------------------- -- Project: OiL - ORB in Lua: An Object Request Broker in Lua -- -- Release: 0.5 alpha -- -- Title : Interoperable Naming Service -- -- Authors: Leonardo S. A. Maciel -- -------------------------------------------------------------------------------- -- Interface: -- -- new() Creates a new instance of a CORBA Naming Service -- -------------------------------------------------------------------------------- -- Notes: -- -- See Naming Service Specification v1.3 -- -- See section 13.6.10.3 of CORBA 3.0 specification for IIOP corbaloc. -- -- -- -- Altough corbaname is specified in section 2.5.3 of Naming Service -- -- Specification v1.3, it is the responsibility of the ORB to implement it. -- -- -- -- There are no limitations on the length of a name component. -- -- There are no limitations on the number of name components in a name. -- -- There are no limitations on the maximum number of bindings in a context. -- -- There are no limitations on the total number of bindings. -- -- There are no limitations on the maximum number of contexts. -- -- There are no limitations on character values or character sequences that -- -- may be used on a name component. -- -- There are no means or policies to deal with orphaned contexts, bindings -- -- or binding iterators. -- -- The CannotProceed exception is raised whenever any but the last name -- -- component of a name is not a context. -- -------------------------------------------------------------------------------- local string = require "string" local table = require "table" local oo = require "oil.oo" local assert = require "oil.assert" local MapWithArrayOfKey = require "loop.collection.MapWithArrayOfKeys" local UnorderedArray = require "loop.collection.UnorderedArray" --[[VERBOSE]] local verbose = require "oil.verbose" module "oil.corba.services.naming" -------------------------------------------------------------------------------- -- Converting between CosNames, Stringified Names and URLs --------------------- local function to_url_escape(s) return string.gsub(s, "([^a-zA-Z0-9;/:%?@&=%+%$,%-_%.!%~*'%(%)])", function(s) return string.format("%%%x", string.byte(s)) end) end local function to_string_escape(s) return string.gsub(s, "([/\\.])", "\\%1") end local function to_string(n) assert.type(n, "table", "name") for i = 1,#n do local id = n[i].id local kind = n[i].kind if kind == "" then if id == "" then n[i] = "." else n[i] = to_string_escape(id) end else n[i] = to_string_escape(id).."."..to_string_escape(kind) end --TODO:[lsam] verificar iso-8859-1 ??? --valid range 32-126 160-255 end local sn = table.concat(n, "/") if sn == "" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/InvalidName:1.0" } end return sn end local function to_name(sn) local n = {} local id = "" local kind = "" local inEscapeMode = false local inKindMode = false local last = "/" --TODO:[lsam] verificar iso-8859-1 ??? --valid range 32-126 160-255 for i=1,string.len(sn)+1 do local cur = string.sub(sn,i,i) if inEscapeMode then if inKindMode then kind = kind..cur else id = id..cur end inEscapeMode = false else if cur == "\\" then inEscapeMode = true elseif cur == "." then inKindMode = true elseif cur == "/" or i == string.len(sn)+1 then if last == "/" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/InvalidName:1.0" } else table.insert(n, {id=id, kind=kind}) id = "" kind = "" inKindMode = false end else if inKindMode then kind = kind..cur else id = id..cur end end end last = cur end return n end -------------------------------------------------------------------------------- -- BindingIterator interface implementation ------------------------------------ BindingIterator = oo.class() function BindingIterator:__init(bindings) return oo.rawnew(self, {bindings = bindings}) end function BindingIterator:next_one() if not self.bindings then assert.exception{"IDL:omg.org/CORBA/OBJECT_NOT_EXIST:1.0"} end local obj = table.remove(self.bindings, 1) return (obj~=nil), obj end function BindingIterator:next_n(how_many) if not self.bindings then assert.exception{"IDL:omg.org/CORBA/OBJECT_NOT_EXIST:1.0"} end local bl = {} if how_many == 0 then assert.exception{"IDL:omg.org/CORBA/BAD_PARAM:1.0"} end for i=1,#self.bindings do if i > how_many then break end table.insert(bl, table.remove(self.bindings,1)) end return (#bl > 0), bl end function BindingIterator:destroy() if not self.bindings then assert.exception{"IDL:omg.org/CORBA/OBJECT_NOT_EXIST:1.0"} end self.bindings = nil end -------------------------------------------------------------------------------- -- NamingContext interface implementation -------------------------------------- NamingContext = oo.class() function NamingContext:__init() return oo.rawnew(self, {bindings = MapWithArrayOfKey()}) end function NamingContext:bind(n, obj) local sn, except = to_string({n[1]}) local r = self.bindings:value(sn) if #n > 1 then if not r then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", why = "missing_node", rest_of_name = n } else if r.binding_type ~= "ncontext" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/CannotProceed:1.0", cxt = self, rest_of_name = n } else table.remove(n,1) return (r.obj):bind(n, obj) end end else if r then assert.exception{"IDL:omg.org/CosNaming/NamingContext/AlreadyBound:1.0"} else self.bindings:add(sn, {binding_type="nobject", obj=obj}) end end end function NamingContext:rebind(n, obj) local sn, except = to_string({n[1]}) local r = self.bindings:value(sn) if #n > 1 then if not r then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", why = "missing_node", rest_of_name = n } else if r.binding_type ~= "ncontext" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/CannotProceed:1.0", cxt = self, rest_of_name = n } else table.remove(n,1) return (r.obj):rebind(n, obj) end end else if r then if r.binding_type ~= "nobject" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", why = "not_object", rest_of_name = {n[1]} } else r.obj = obj end else self.bindings:add(sn, {binding_type="nobject", obj=obj}) end end end function NamingContext:bind_context(n, nc) if not nc then assert.exception{"IDL:omg.org/CORBA/BAD_PARAM:1.0"} end local sn, except = to_string({n[1]}) local r = self.bindings:value(sn) if #n > 1 then if not r then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", why = "missing_node", rest_of_name = n } else if r.binding_type ~= "ncontext" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/CannotProceed:1.0", cxt = self, rest_of_name = n } else table.remove(n,1) return (r.obj):bind_context(n, nc) end end else if r then assert.exception{"IDL:omg.org/CosNaming/NamingContext/AlreadyBound:1.0"} else self.bindings:add(sn, {binding_type="ncontext", obj=nc}) end end end function NamingContext:rebind_context(n, nc) if not nc then assert.exception{"IDL:omg.org/CORBA/BAD_PARAM:1.0"} end local sn, except = to_string({n[1]}) local r = self.bindings:value(sn) if #n > 1 then if not r then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", why = "missing_node", rest_of_name = n } else if r.binding_type ~= "ncontext" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/CannotProceed:1.0", cxt = self, rest_of_name = n } else table.remove(n,1) return (r.obj):rebind_context(n, nc) end end else if r then if r.binding_type ~= "ncontext" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", why = "not_context", rest_of_name = {n[1]} } else r.obj = nc end else self.bindings:add(sn, {binding_type="ncontext", obj=nc}) end end end function NamingContext:resolve(n) local sn, except = to_string({n[1]}) local r = self.bindings:value(sn) if not r then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", why = "missing_node", rest_of_name = n } elseif #n > 1 then if r.binding_type ~= "ncontext" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/CannotProceed:1.0", cxt = self, rest_of_name = n } else table.remove(n,1) return (r.obj):resolve(n) end else return r.obj end end function NamingContext:unbind(n) local sn, except = to_string({n[1]}) local r = self.bindings:value(sn) if not r then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", why = "missing_node", rest_of_name = n } elseif #n > 1 then if r.binding_type ~= "ncontext" then assert.exception{"IDL:omg.org/CosNaming/NamingContext/CannotProceed:1.0", cxt = self, rest_of_name = n } else table.remove(n,1) return (r.obj):unbind(n) end else self.bindings:remove(sn) end end function NamingContext:new_context() local nc = NamingContext() return nc end function NamingContext:bind_new_context(n) local nc = self:new_context() self:bind_context(n, nc) return nc end function NamingContext:destroy() if self.bindings:size() > 0 then assert.exception{"IDL:omg.org/CosNaming/NamingContext/NotEmpty:1.0" } else self.bindings = nil end end local function BindingList(b, how_many) return bl, bi end function NamingContext:list(how_many) local i = 1 local bl = {} local bi = {} for i=1,self.bindings:size() do local k = self.bindings:keyat(i) local v = self.bindings:valueat(i) if i > how_many then table.insert(bi, {binding_name=to_name(k), binding_type=v.binding_type}) else table.insert(bl, {binding_name=to_name(k), binding_type=v.binding_type}) end end return bl, BindingIterator(bi) end -------------------------------------------------------------------------------- -- NamingContextExt interface implementation ----------------------------------- NamingContextExt = oo.class({}, NamingContext) function NamingContextExt:to_string(n) return to_string(n) end function NamingContextExt:to_name(sn) return to_name(sn) end function NamingContextExt:to_url(addr, sn) local url = {"corbaname:", addr} if not addr or addr == "" then assert.exception{"IDL:omg.org/CosNaming/NamingContextExt/InvalidAddress:1.0"} end if sn and string.len(sn) > 0 then local esn = to_url_escape(sn) table.insert(url, "#") table.insert(url, esn) end return table.concat(url) end function NamingContextExt:resolve_str(sn) return self:resolve(to_name(sn)) end -------------------------------------------------------------------------------- -- Resolve initial Name Service ------------------------------------------------ -- @return 1 table CORBA object which is the root context of the Naming Service. -- @return 2 string Repository ID of interface supported by the Naming Service. -- @return 3 string Object key used in the Naming Service object reference. function new() return NamingContextExt(), "NameService", "IDL:omg.org/CosNaming/NamingContextExt:1.0" end