25 |
# Set of classes that implement the XML-RPC server driver for GNUe Comm. |
# Set of classes that implement the XML-RPC server driver for GNUe Comm. |
26 |
# |
# |
27 |
# NOTES: |
# NOTES: |
28 |
# Requires py-xmlrpc from http://sf.net/projects/python-xmlrpc |
# Requires py-xmlrpc from http://sf.net/projects/py-xmlrpc |
29 |
# |
# |
30 |
# |
# |
31 |
# Server Parameters: |
# Server Parameters: |
32 |
# |
# |
33 |
# port The port that the service is located on |
# port The port that the service is located on |
34 |
|
# loglevel Loglevel of the internal server |
35 |
# |
# |
36 |
|
|
37 |
|
|
47 |
|
|
48 |
|
|
49 |
from gnue.common import GComm, GDebug |
from gnue.common import GComm, GDebug |
50 |
from gnue.common.commdrivers._helpers import ObjectLibrarian |
from gnue.common.commdrivers._helpers import ObjectLibrarian,ObjectEnabler |
51 |
from gnue.common.commdrivers._directory import DirectoryServer |
from gnue.common.commdrivers._directory import DirectoryServer |
52 |
from gnue.common.commdrivers import GCommBase |
from gnue.common.commdrivers import GCommBase |
53 |
|
|
80 |
# |
# |
81 |
# ServerAdapter |
# ServerAdapter |
82 |
# |
# |
83 |
class ServerAdapter(DirectoryServer.DirectoryServer): |
class ServerAdapter(ObjectEnabler.ObjectEnabler): |
84 |
|
|
85 |
def __init__(self, rpcdef, bindings, params): |
def __init__(self, rpcdef, bindings, params): |
86 |
|
|
95 |
self.server=XMLRPC_Server() |
self.server=XMLRPC_Server() |
96 |
|
|
97 |
|
|
98 |
## Build up Service Directory |
## Build up Service Directory and enable object dispatching |
99 |
DirectoryServer.DirectoryServer.__init__(self, rpcdef, \ |
ObjectEnabler.ObjectEnabler.__init__(self, rpcdef, \ |
100 |
bindings, params) |
bindings, params) |
101 |
|
|
102 |
if hasattr(params,'loglevel'): |
if hasattr(params,'loglevel'): |
103 |
self._loglevel = params['loglevel'] |
self._loglevel = params['loglevel'] |
111 |
self.server.setOnErr(self.OnErr) |
self.server.setOnErr(self.OnErr) |
112 |
|
|
113 |
def serve(self): |
def serve(self): |
114 |
while 1: |
quit=0 |
115 |
|
while quit==0: |
116 |
try: |
try: |
117 |
self.server.work() |
self.server.work() |
118 |
# you could set a timeout if desired |
# you could set a timeout if desired |
119 |
except: |
except: |
120 |
e = sys.exc_info() |
e = sys.exc_info() |
121 |
if e[0] in (KeyboardInterrupt, SystemExit): |
if e[0] in (KeyboardInterrupt, SystemExit): |
122 |
raise e[0], e[1], e[2] |
# shut down server without showing error message |
123 |
traceback.print_exc() |
quit=1 |
124 |
|
# raise e[0], e[1], e[2] |
125 |
|
else: |
126 |
|
print "*" * 60 |
127 |
|
print "Error occured on server:" |
128 |
|
print "*" * 60 |
129 |
|
traceback.print_exc() |
130 |
|
print "*" * 60 |
131 |
|
print "\n\n" |
132 |
|
|
133 |
def addRpMethod(self,object,parent,binding): |
def addRpMethod(self,object,parent,binding): |
134 |
|
|
155 |
binding}) |
binding}) |
156 |
|
|
157 |
|
|
158 |
def OnErr(server,source): |
def OnErr(self,server,source): |
159 |
print _("Internal server error occured:\n"+ |
print _("Internal server error occured:\n"+ |
160 |
" server %s \n on source %s.") % (server,source) |
" server %s \n on source %s.") % (server,source) |
161 |
return xmlrpc.ONERR_KEEP_WORK |
return xmlrpc.ONERR_KEEP_WORK |
|
|
|
|
|
|
|
# |
|
|
# Call the requested method |
|
|
# |
|
|
def call(self, method, params): |
|
|
if self._loglevel>0: |
|
|
print _("Dispatching: "), method, params |
|
|
|
|
|
|
|
|
## Check if the Method is part of a service or a pointer to a |
|
|
## single object |
|
|
## |
|
|
## Call to an object: method="_Management:235423456_.getAttr" |
|
|
## params="" |
|
|
## Call to an method: (of a service=one object) |
|
|
## method="DonutPlace.Management.Restart" |
|
|
|
|
|
if method[0]=='[': |
|
|
# call to an object |
|
|
# 1. get the object from the objectlibrarian |
|
|
# 2. check, if the object is supported by the gfd |
|
|
try: |
|
|
i=string.index(method,']',1) |
|
|
objhandle=method[1:i] |
|
|
method=method[i+2:] |
|
|
except ValueError: |
|
|
raise AttributeError, \ |
|
|
_("Wrong format of object handler ")+\ |
|
|
_("in method call %s") % method |
|
|
# TODO check in service dir, if obj is supported or not |
|
|
o=ObjectLibrarian.retrieveObject(objhandle) |
|
|
try: |
|
|
server_method=getattr(o,method) |
|
|
server_attribute=None |
|
|
except AttributeError: |
|
|
server_method=None |
|
|
try: |
|
|
server_attribute=getattr(o,method[4:]) |
|
|
except AttributeError: |
|
|
|
|
|
if method!="_close": |
|
|
msg=_("Internal XMLRPC server error: method %s can be ")% \ |
|
|
method +\ |
|
|
_("found in the directory (build out of a .grpc file),")+\ |
|
|
_(" but the object doesn't contain this method/attribut.")+\ |
|
|
_(" Please check you .grpc file for wrong return types.") |
|
|
|
|
|
raise AttributeError, msg |
|
|
|
|
|
if method!="_close": |
|
|
direntry = self.getMethodDirEntry(o._type+"."+method) |
|
|
signature=direntry['signature'] |
|
|
else: |
|
|
signature= ('string',) |
|
|
|
|
|
else: |
|
|
|
|
|
# call to a service method or a helper call (get/set) for |
|
|
# a service attribut |
|
|
try: |
|
|
direntry = self.getMethodDirEntry(method) |
|
|
server_method = direntry['binding'] |
|
|
server_attribute = None |
|
|
|
|
|
# check if it is an real method (binding -> method) |
|
|
# or an get/set method for an attribut (binding-> attribut) |
|
|
if (type(server_method)!=type(self.call)): |
|
|
server_attribute = server_method |
|
|
server_method=None |
|
|
|
|
|
signature=direntry['signature'] |
|
|
|
|
|
if (server_method==None) and (server_attribute==None): |
|
|
raise AttributeError, \ |
|
|
_("Server XML-RPC method %s is not ")% method +\ |
|
|
_("bound to real method") |
|
|
except KeyError: |
|
|
raise AttributeError, \ |
|
|
_("Server does not have XML-RPC ") +\ |
|
|
_("procedure %s") % method |
|
|
try: |
|
|
# |
|
|
pass |
|
|
# TODO: Compare submitted attributs with signature |
|
|
except KeyError: |
|
|
raise AttributeError, \ |
|
|
_("Server XML-RPC ") +\ |
|
|
_("procedure %s accepts just %s as attributs") % (method,attr) |
|
162 |
|
|
163 |
|
|
|
# replace object handles in param with the real object |
|
|
counter=0 |
|
|
while counter<len(params): |
|
|
p=params[counter] |
|
|
if type(p)==type(""): |
|
|
if (len(p)==42) and (p[0]=="[") and (p[41]=="]"): |
|
|
try: |
|
|
p=p[1:41] |
|
|
obj=ObjectLibrarian.retrieveObject(p) |
|
|
newp=params[0:counter-1]+(obj,)+params[counter+1:] |
|
|
params=newp |
|
|
except: |
|
|
pass |
|
|
counter=counter+1; |
|
|
|
|
|
# check if it is an real method (binding -> method) |
|
|
# or an get/set method for an attribut (binding-> attribut) |
|
|
|
|
|
if (server_method!=None): |
|
|
|
|
|
# call method with params |
|
|
result=server_method(*params) |
|
|
|
|
|
# check if it's the close object method |
|
|
elif (method=="_close"): |
|
|
|
|
|
result=self.releaseDynamicObject(o) |
|
|
|
|
|
else: |
|
|
|
|
|
## check wether its the set or the get method for the attribut |
|
|
mparts=string.splitfields(method,'.') |
|
|
mparts.reverse() |
|
|
calltype=mparts[0] |
|
|
calltype=calltype[:4] |
|
|
GDebug.printMesg(7,'method %s has calling type %s' %\ |
|
|
(method,calltype)) |
|
|
if calltype=='set_': |
|
|
# setAttribut method |
|
|
server_attribute=params[0] |
|
|
elif calltype=='get_': |
|
|
# getAttribut method |
|
|
result=server_attribute |
|
|
else: |
|
|
raise AttributeError, \ |
|
|
_("Internal Server XML-RPC error: method type") +\ |
|
|
_("(get/set attribute) couldn't be detected (method %s)") \ |
|
|
% method |
|
|
|
|
|
|
|
|
# replace real object in param with an object handle |
|
|
if type(result)==type(self): ## both should be instances |
|
|
ObjectLibrarian.archiveObject(result) |
|
|
|
|
|
# get the type of the result |
|
|
rtype=signature[0] |
|
|
# delete the surrounding brackets < > |
|
|
rtype=rtype[1:len(rtype)-1] |
|
|
# store typeinfo in new object |
|
|
result._type=rtype |
|
|
|
|
|
result=ObjectLibrarian.getObjectReference(result) |
|
|
self.registerDynamicObject(result,rtype) |
|
|
|
|
|
# check for empty results (not allowed for XMLRPC) |
|
|
if result==None: |
|
|
GDebug.printMesg(3,'Transform result None into 1') |
|
|
result=1 |
|
|
|
|
|
return result |
|
|
|
|
164 |
def registerDynamicObject(self,objhandle,type): |
def registerDynamicObject(self,objhandle,type): |
165 |
# |
# |
166 |
# add new methods to the xmlrpc server |
# add new methods to the xmlrpc server |
194 |
|
|
195 |
# remove the method to close this object |
# remove the method to close this object |
196 |
self.server.removeMethods({"["+objhandle+"]._close":None}) |
self.server.removeMethods({"["+objhandle+"]._close":None}) |
|
|
|
|
def releaseDynamicObject(self,object): |
|
|
# delete bindings for this object in the xmlrpc method directory |
|
|
self.deregisterDynamicObject(object) |
|
|
# release object for Object Librarian |
|
|
ObjectLibrarian.deferenceObject(object) |
|
197 |
|
|
198 |
|
|
199 |
class XMLRPC_Server(xmlrpc.server): |
class XMLRPC_Server(xmlrpc.server): |
211 |
# del self._o.comtab[name] |
# del self._o.comtab[name] |
212 |
# or |
# or |
213 |
# self._o.removeMethods(d) |
# self._o.removeMethods(d) |
|
|
|
|
############################################################################## |
|
|
# |
|
|
# Used internally by the XML-RPC server to proxy |
|
|
# between Object-by-Ref and actual objects. |
|
|
# |
|
|
class _ObjectByReferenceHandler: |
|
|
|
|
|
def __init__(self, oclass): |
|
|
self._class = oclass |
|
|
|
|
|
# If this makes absolutely no sense, move on and trust the code :) |
|
|
def requestHandler(self, method, *params, **args): |
|
|
|
|
|
if len(params): |
|
|
|
|
|
# If parameters were passed, the first one is always the handle |
|
|
refid = params[0] |
|
|
|
|
|
# The object's real method doesn't expect to receive the object handle |
|
|
params = params[1:] |
|
|
|
|
|
else: |
|
|
|
|
|
try: |
|
|
|
|
|
# If only named parameters are present, then |
|
|
# obj_handle should be the object handle... |
|
|
refid = args['obj_handle'] |
|
|
|
|
|
# The object's real method doesn't expect to receive the object handle |
|
|
del args['obj_handle'] |
|
|
|
|
|
except KeyError: |
|
|
raise StandardError, _('Object handle not returned') # TODO |
|
|
|
|
|
try: |
|
|
return ObjectLibrarian. \ |
|
|
retrieveObject(refid).__dict__[method](*params, **args) |
|
|
except KeyError: |
|
|
|
|
|
# Attempt to use an invalid objecthandle |
|
|
raise StandardError, _('Invalid object handle') # TODO |
|
|
|
|