commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnue] r7902 - in trunk/gnue-common/src/rpc: . drivers drivers/xmlrpc


From: johannes
Subject: [gnue] r7902 - in trunk/gnue-common/src/rpc: . drivers drivers/xmlrpc
Date: Wed, 14 Sep 2005 12:26:13 -0500 (CDT)

Author: johannes
Date: 2005-09-14 12:26:12 -0500 (Wed, 14 Sep 2005)
New Revision: 7902

Modified:
   trunk/gnue-common/src/rpc/client.py
   trunk/gnue-common/src/rpc/drivers/Base.py
   trunk/gnue-common/src/rpc/drivers/xmlrpc/ClientAdapter.py
   trunk/gnue-common/src/rpc/drivers/xmlrpc/ServerAdapter.py
   trunk/gnue-common/src/rpc/drivers/xmlrpc/typeconv.py
   trunk/gnue-common/src/rpc/server.py
Log:
Added object support to xmlrpc


Modified: trunk/gnue-common/src/rpc/client.py
===================================================================
--- trunk/gnue-common/src/rpc/client.py 2005-09-14 17:25:29 UTC (rev 7901)
+++ trunk/gnue-common/src/rpc/client.py 2005-09-14 17:26:12 UTC (rev 7902)
@@ -138,12 +138,13 @@
   print 'datetimetest:', repr (obj.datetimetest ())
   print 'booltest:', repr (obj.booltest ())
 
-  #subobj = obj.objtest ()
-  #print 'objtest:', repr (subobj)
-  # print 'subobj.test'
-  # subobj.test ()
-  #del subobj
+  subobj = obj.objtest ()
+  print 'objtest:', repr (subobj)
+  print 'subobj.test', subobj.test ()
 
+  subobj.setName ('Foobar')
+  print "Subobj.printIt () ==", subobj.printIt ()
+
   print 'testing exception ...'
 
   try:
@@ -185,6 +186,18 @@
   v = obj.roundtrip (o)
   print "Result:", repr (v), type (v)
 
+  other = obj.objtest ('barbaz')
+  print "Other object:", other.printIt ()
+  
+  res = subobj.argcheck (other)
+  print "subobj.argcheck (other)", res
+
+  res = subobj.dictcheck (other, {'buddy': other})
+  print "Result-Object (buddy)=", res.printIt ()
+
+  subobj.close ()
+  other.close ()
+
   print 'shutting down server ...'
   try:
     # This will raise an exception because the server will not even answer any

Modified: trunk/gnue-common/src/rpc/drivers/Base.py
===================================================================
--- trunk/gnue-common/src/rpc/drivers/Base.py   2005-09-14 17:25:29 UTC (rev 
7901)
+++ trunk/gnue-common/src/rpc/drivers/Base.py   2005-09-14 17:26:12 UTC (rev 
7902)
@@ -260,6 +260,21 @@
 
 
   # ---------------------------------------------------------------------------
+  # Attribute access
+  # ---------------------------------------------------------------------------
+
+  def __getattr__ (self, name):
+    """
+    Support for nested methods, e.g. system.listMethods.
+    @param name: name of the attribute in question
+
+    @returns: L{ProxyMethod} instance pointing to the nested method
+    """
+
+    return ProxyMethod (self._adapter, "%s.%s" % (self._methodname, name))
+
+
+  # ---------------------------------------------------------------------------
   # Nice string representation
   # ---------------------------------------------------------------------------
 

Modified: trunk/gnue-common/src/rpc/drivers/xmlrpc/ClientAdapter.py
===================================================================
--- trunk/gnue-common/src/rpc/drivers/xmlrpc/ClientAdapter.py   2005-09-14 
17:25:29 UTC (rev 7901)
+++ trunk/gnue-common/src/rpc/drivers/xmlrpc/ClientAdapter.py   2005-09-14 
17:26:12 UTC (rev 7902)
@@ -163,8 +163,8 @@
 
     checktype (method, basestring)
 
-    __args = tuple ([typeconv.python_to_rpc (arg, client.InvalidParameter)
-              for arg in args])
+    __args = tuple ([typeconv.python_to_rpc (arg, self.__unwrapProxy) \
+        for arg in args])
     try:
       request = xmlrpclib.dumps (__args, method, allow_none = True)
       result = self._transport.request (self.__remote, "/RPC2", request,
@@ -183,7 +183,8 @@
     except socket.error:
       raise errors.AdminError, errors.getException () [2]
 
-    return gLeave (9, typeconv.rpc_to_python (result, client.InvalidParameter))
+    return gLeave (9, typeconv.rpc_to_python (result, self.__wrapProxy,
+      client.InvalidParameter))
 
 
   # ---------------------------------------------------------------------------
@@ -192,3 +193,102 @@
 
   def __str__ (self):
     return "XML-RPC client adapter for %s" % self.__remote
+
+
+  # ---------------------------------------------------------------------------
+  # Wrap an ObjectProxy instance around a server object
+  # ---------------------------------------------------------------------------
+
+  def __wrapProxy (self, item):
+
+    return ObjectProxy (self, item)
+
+
+  # ---------------------------------------------------------------------------
+  # Unwrap an ObjectProxy instance so it can be sent through xmlrpc
+  # ---------------------------------------------------------------------------
+
+  def __unwrapProxy (self, proxy):
+
+    return proxy._storedItem
+
+
+
+# =============================================================================
+# Proxy class for objects living on the server
+# =============================================================================
+
+class ObjectProxy (Base.ServerProxy):
+  """
+  A proxy class providing an execution context of server side objects.
+  """
+  
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, adapter, item):
+
+    Base.ServerProxy.__init__ (self, adapter)
+    self._storedItem = item
+
+
+  # ---------------------------------------------------------------------------
+  # Remove the object from the server's object store
+  # ---------------------------------------------------------------------------
+
+  def close (self):
+    """
+    Remove the object from the server's object store. Further access to this
+    object will lead to an exception
+    """
+
+    self._adapter._callMethod_ ('_remove_object', self._storedItem)
+
+
+  # ---------------------------------------------------------------------------
+  # Attribute access
+  # ---------------------------------------------------------------------------
+
+  def __getattr__ (self, name):
+
+    result = ObjectProxyMethod (self._adapter, name, self._storedItem)
+    self.__dict__ [name] = result
+
+    return result
+
+
+
+# =============================================================================
+# Callable environment for object proxies
+# =============================================================================
+
+class ObjectProxyMethod (Base.ProxyMethod):
+  """
+  Provide a callable environment for an L{ObjectProxy}. This will call the 
+  "_object_call" method at the remote server, giving the id-dictionary and the
+  method-name as first and second argument.
+  """
+
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, adapter, methodname, item):
+
+    Base.ProxyMethod.__init__ (self, adapter, methodname)
+    self._storeItem = item
+
+
+  # ---------------------------------------------------------------------------
+  # Call a method
+  # ---------------------------------------------------------------------------
+
+  def __call__ (self, *args, **params):
+
+    # Add the id-dictionary and the methodname to the rpc-call
+    nargs = tuple ([self._storeItem, self._methodname] + list (args))
+    return self._adapter._callMethod_ ('_object_call', *nargs, **params)
+
+  def __str__ (self):
+    return "ObjectProxyMethod '%s' of %s" % (self._methodname, self._storeItem)

Modified: trunk/gnue-common/src/rpc/drivers/xmlrpc/ServerAdapter.py
===================================================================
--- trunk/gnue-common/src/rpc/drivers/xmlrpc/ServerAdapter.py   2005-09-14 
17:25:29 UTC (rev 7901)
+++ trunk/gnue-common/src/rpc/drivers/xmlrpc/ServerAdapter.py   2005-09-14 
17:26:12 UTC (rev 7902)
@@ -34,7 +34,17 @@
 from gnue.common.utils import http
 
 
+# =============================================================================
+# Exceptions
+# =============================================================================
 
+class ObjectNotFoundError (errors.SystemError):
+  def __init__ (self, item):
+    msg = u_("Element of type '%(type)s' with id '%(id)s' not found in store")\
+          % {'type': item ['__rpc_datatype__'], 'id': item ['__id__']}
+    errors.SystemError.__init__ (self, msg)
+
+
 # =============================================================================
 # Class implementing an XML-RPC server adapter
 # =============================================================================
@@ -75,12 +85,19 @@
     self._tcpServer = serverClass ((self._bindto, self._port),
         logRequests = parameters.get ('loglevel', 0), adapter = self)
 
+    # Store with all valid objects created by the server
+    self._objectStore = {}
+
     # Register the python object to be served as well as the introspection
     # functions (system.list_methods,system.list_help, system.list_signatures)
     self._tcpServer.register_instance (self.instance)
     self._tcpServer.register_introspection_functions ()
 
+    # Register functions for object support: calling and removing
+    self._tcpServer.register_function (self._object_call)
+    self._tcpServer.register_function (self._remove_object)
 
+
   # ---------------------------------------------------------------------------
   # Dispatch a method with the given parameters
   # ---------------------------------------------------------------------------
@@ -101,13 +118,65 @@
     checktype (method, basestring)
     checktype (parameters, tuple)
     
-    params = typeconv.rpc_to_python (parameters, server.InvalidParameter)
+    params = typeconv.rpc_to_python (parameters, self._fetchFromStore,
+        server.InvalidParameter)
     result = self._tcpServer._dispatch (method, params)
 
-    return gLeave (9, typeconv.python_to_rpc (result, server.InvalidParameter))
+    return gLeave (9, typeconv.python_to_rpc (result, self._updateStore))
 
 
   # ---------------------------------------------------------------------------
+  # Call a procedure of a given stored object
+  # ---------------------------------------------------------------------------
+
+  def _object_call (self, storedObject, method, *parameters):
+
+    assert gEnter (9)
+    return gLeave (9, getattr (storedObject, method) (*parameters))
+
+
+  # ---------------------------------------------------------------------------
+  # Remove an object from the object store
+  # ---------------------------------------------------------------------------
+
+  def _remove_object (self, item):
+
+    assert gEnter (9)
+
+    if id (item) in self._objectStore:
+      del self._objectStore [id (item)]
+
+    gLeave (9)
+
+
+  # ---------------------------------------------------------------------------
+  # Add an object to the store or update it's reference
+  # ---------------------------------------------------------------------------
+
+  def _updateStore (self, item):
+
+    gEnter (9)
+
+    result = {'__id__': id (item), '__rpc_datatype__': 'object'}
+    self._objectStore [id (item)] = item
+
+    return gLeave (9, result)
+
+
+  # ---------------------------------------------------------------------------
+  # Fetch a real object from the store, identified by it's id-dictionary
+  # ---------------------------------------------------------------------------
+
+  def _fetchFromStore (self, item):
+
+    try:
+      return self._objectStore [item ['__id__']]
+
+    except KeyError:
+      raise ObjectNotFoundError, item
+
+
+  # ---------------------------------------------------------------------------
   # Nice string representation
   # ---------------------------------------------------------------------------
 

Modified: trunk/gnue-common/src/rpc/drivers/xmlrpc/typeconv.py
===================================================================
--- trunk/gnue-common/src/rpc/drivers/xmlrpc/typeconv.py        2005-09-14 
17:25:29 UTC (rev 7901)
+++ trunk/gnue-common/src/rpc/drivers/xmlrpc/typeconv.py        2005-09-14 
17:26:12 UTC (rev 7902)
@@ -28,15 +28,39 @@
 from gnue.common.utils import GDateTime
 
 # -----------------------------------------------------------------------------
+# Check wether a given item is an id-dictionary representing a server object
+# -----------------------------------------------------------------------------
+
+def is_rpc_object (value):
+  """
+  Check wether a given value is a structure representing a server object.
+
+  @param value: the python value to be checked
+  @returns: True for a remote server object, False otherwise.
+  """
+
+  if isinstance (value, dict):
+    k = value.keys ()
+    k.sort ()
+
+    result = (k == ['__id__', '__rpc_datatype__'])
+  else:
+    result = False
+
+  return result
+
+
+# -----------------------------------------------------------------------------
 # Convert native Python type to xmlrpc's type
 # -----------------------------------------------------------------------------
 
-def python_to_rpc (value, exception):
+def python_to_rpc (value, wrapObject):
   """
   Convert a value from native python type into a type acceptable to xmlrpc. 
 
   @param value: the native python value to be converted
-  @param exception: exception to be raised if the value couldn't get converted
+  @param wrapObject: if the value is not one of the base types to be converted,
+    this function will be used to wrap the value
   
   The following type conversions are performed.
 
@@ -50,8 +74,6 @@
 
   For lists and tuples the conversion will be applied to each element. For
   dictionaries the conversion will be applied to the key as well as the value.
-  If the value is none of the above datatypes the given exception will be
-  raised.
   """
 
   if value is None:
@@ -75,23 +97,26 @@
 
   # Date/Time
   elif isinstance (value, mx.DateTime.DateTimeType):
+    print "$" * 50, "FROM mx.DT:", repr (value)
     return xmlrpclib.DateTime ("%04d-%02d-%02d %02d:%02d:%09.6f" % (value.year,
       value.month, value.day, value.hour, value.minute, value.second))
 
   elif isinstance (value, mx.DateTime.DateTimeDeltaType):
+    print "%" * 50, "FROM mx.TM:", repr (value)
     return xmlrpclib.DateTime ("%02d:%02d:%09.6f" % (value.hour, value.minute,
       value.second))
 
   elif isinstance (value, (datetime.datetime, datetime.date, datetime.time)):
+    print "?" * 50, "FROM dt:", repr (value), "=", value.isoformat ()
     return xmlrpclib.DateTime (value.isoformat ())
 
   # List
   elif isinstance (value, list):
-    return [python_to_rpc (element, exception) for element in value]
+    return [python_to_rpc (element, wrapObject) for element in value]
 
   # Tuple
   elif isinstance (value, tuple):
-    return tuple ([python_to_rpc (element, exception) for element in value])
+    return tuple ([python_to_rpc (element, wrapObject) for element in value])
 
   # Dictionary
   elif isinstance (value, dict):
@@ -108,12 +133,15 @@
         key = ''
 
       elif not isinstance (key, str):
-        key = python_to_rpc (key, exception)
+        key = python_to_rpc (key, wrapObject)
 
-      result [key] = python_to_rpc (val, exception)
+      result [key] = python_to_rpc (val, wrapObject)
 
     return result
 
+  elif wrapObject is not None:
+    return wrapObject (value)
+
   else:
     raise exception, repr (value)
 
@@ -122,11 +150,12 @@
 # Convert xmlrpc's type to native Python type
 # -----------------------------------------------------------------------------
 
-def rpc_to_python (value, exception):
+def rpc_to_python (value, wrapObject, exception):
   """
   Convert a value from xmlrpc types into native python types.
 
   @param value: xmlrpc value
+  @param wrapObject: function to be called, if L{is_rpc_object} returns True
   @param exception: exception to be raised if no conversion is available
 
   The following conversions are performed:
@@ -164,21 +193,27 @@
 
   # Date/Time/DateTime
   elif isinstance (value, xmlrpclib.DateTime):
-    return GDateTime.parseISO (value.value)
+    result = GDateTime.parseISO (value.value)
+    print "#" * 50, repr (result), repr (value.value)
+    return result
 
   # List
   elif isinstance (value, list):
-    return [rpc_to_python (element, exception) for element in value]
+    return [rpc_to_python (element, wrapObject, exception) for element in 
value]
 
   # Tuple
   elif isinstance (value, tuple):
-    return tuple ([rpc_to_python (element, exception) for element in value])
+    return tuple ([rpc_to_python (e, wrapObject, exception) for e in value])
 
   # Dictionary
+  elif is_rpc_object (value):
+    return wrapObject (value)
+
   elif isinstance (value, dict):
     result = {}
     for (key, val) in value.items ():
-      result [rpc_to_python (key, exception)] = rpc_to_python (val, exception)
+      result [rpc_to_python (key, wrapObject, exception)] = \
+          rpc_to_python (val, wrapObject, exception)
     return result
 
   else:

Modified: trunk/gnue-common/src/rpc/server.py
===================================================================
--- trunk/gnue-common/src/rpc/server.py 2005-09-14 17:25:29 UTC (rev 7901)
+++ trunk/gnue-common/src/rpc/server.py 2005-09-14 17:26:12 UTC (rev 7902)
@@ -110,14 +110,35 @@
     pass
 
   class subobject:
-    def __init__ (self):
+    def __init__ (self, name = None):
       print "Initializing subobject"
+      self.name = name
 
-    def test (self):
-      print "Testing subobject"
+    def printIt (self):
+      print "Current Name is '%s'" % self.name
+      return self.name
 
+    def setName (self, name):
+      print "Setting new name to:", name
+      self.name = name
+
+    def test (self, *args):
+      print "Testing subobject:", args
+
+    def argcheck (self, other):
+      print "Hi, my name is", self.name
+      print "Your name is", other.name
+      return other.name
+
+    def dictcheck (self, other, adict):
+      print "I am:", self.name
+      print "Other is:", other.name
+      result = adict ['buddy']
+      print "dict [buddy] is:", result.name, id (result)
+      return result
+
     def __del__ (self):
-      print "Destroying subobject"
+      print "Destroying subobject", id (self)
 
   class servertest:
 
@@ -139,8 +160,9 @@
     def booltest (self):
       return True
 
-    def objtest (self):
-      return subobject ()
+    def objtest (self, name = None):
+      print "Building a subobject ..."
+      return subobject (name)
 
     def roundtrip (self, value):
       print "SERVER:", repr (value), type (value)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]