[Top][All Lists]
[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)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r7902 - in trunk/gnue-common/src/rpc: . drivers drivers/xmlrpc,
johannes <=