2
# This file is part of GNU Enterprise.
4
# GNU Enterprise is free software; you can redistribute it
5
# and/or modify it under the terms of the GNU General Public
6
# License as published by the Free Software Foundation; either
7
# version 2, or (at your option) any later version.
9
# GNU Enterprise is distributed in the hope that it will be
10
# useful, but WITHOUT ANY WARRANTY; without even the implied
11
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12
# PURPOSE. See the GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public
15
# License along with program; see the file COPYING. If not,
16
# write to the Free Software Foundation, Inc., 59 Temple Place
17
# - Suite 330, Boston, MA 02111-1307, USA.
19
# Copyright 2001-2005 Free Software Foundation
22
# pyro/ServerAdapter.py
25
# Set of classes that implement the Pyro server driver for GNUe Comm.
28
# Requires pyro from pyro.sf.net
32
# port The port that the service is located on
36
from gnue.common.apps import errors, GDebug
37
from gnue.common.rpc import server
38
from gnue.common.rpc.drivers import Base
39
from gnue.common.rpc.drivers._helpers import ObjectLibrarian, ObjectEnabler
41
import string, sys, os, posixpath, urllib, socket
46
from Pyro.protocol import getHostname
47
from Pyro.errors import PyroError,NamingError
50
tmsg = _("\nUnable to load Pyro. To use the Pyro interface, \n"
51
"please install pyro from:\n http://pyro.sf.net/")
52
raise GComm.AdapterInitializationError, tmsg
55
# Mapping from GRPC's datatype to XML-RPC datatypes
60
'date': 'dateTime.iso8601',
66
##############################################################################
70
class ServerAdapter(Base.Server):
72
def __init__(self, rpcdef, bindings, params):
74
self._port = params['port']
78
if params.has_key('bindto'):
79
self._bindto = params['bindto']
81
self._bindto = '' # bind to all interfaces
83
if params.has_key('allowed_hosts'):
84
# TODO: Remove spaces, etc.
85
self._allowed_hosts = string.split(params['allowed_hosts'],',')
87
self._allowed_hosts = [''] # allow access from all hosts
89
if params.has_key('loglevel'):
90
self._loglevel = params['loglevel']
94
self.pyro_group = ':GComm'
95
# TODO: set pyro_group to other name, depending on grpc
97
# initialize pyro server
98
Pyro.core.initServer()
99
Pyro.config.PYRO_NS_DEFAULTGROUP=self.pyro_group
100
self.daemon = Pyro.core.Daemon()
102
# locate the name server
103
if not hasattr(self,'ns'):
104
locator = Pyro.naming.NameServerLocator()
105
GDebug.printMesg(9,'PYRO: searching for Naming Service...')
106
self.ns = locator.getNS()
107
GDebug.printMesg(9,'Naming Service found at %s (%s) %s.' % \
108
(self.ns.URI.address,
109
(Pyro.protocol.getHostname(self.ns.URI.address) or '??'),
112
# make sure our namespace group exists
114
self.ns.createGroup(self.pyro_group)
118
self.daemon.useNameServer(self.ns)
120
self.mapObjects(rpcdef,bindings)
124
# Return an exception
126
def raiseException(self, exception, message, event=None):
132
##########################################################################
135
# enter the service loop.
136
GDebug.printMesg(9,'Starting pyro daemon loop.')
139
# daemon.setTimeout(5)
140
self.daemon.requestLoop()
141
except KeyboardInterrupt:
142
print 'shutting down gracefully.'
143
# todo: disconnect all obj.
144
#daemon.disconnect(obj)
145
self.daemon.shutdown()
150
# Create an internal "service directory"
152
def mapObjects(self, object, bindings, parent=None):
154
# For servicable objects, maintain a complete "path" for reference
155
if object._type in ('RpService','RpMethod','RpObject'):
156
if parent and hasattr(parent,'_path'):
157
object._path = "%s.%s" % (parent._path, object.name)
159
object._path = object.name
163
## Add binding informations to the objects
165
## services are static objects and
166
## objects are dynamic ones
168
if hasattr(object,'binding'):
171
if bindings.has_key(object.binding):
172
GDebug.printMesg(9,'GNURPC Binding Information:');
173
GDebug.printMesg(9,' * %s is bound to \n * %s' % \
174
(object.binding,bindings[object.binding]))
176
# for services create an "static" object
177
if object._type == 'RpService':
178
object._realbinding=bindings[object.binding]()
179
# TODO: Clearup this "static" object
183
# in all other cases just save the binding information
184
object._realbinding=bindings[object.binding]
187
# RpObject normaly don't need binding information, because
188
# they are bound dynamicly
189
if object._type != 'RpObject':
191
print u_("Missing Binding information. Please add binding "
192
"information for %s") % object.binding
195
# care for bindings in all Services
196
if object._type == 'RpService':
197
if hasattr(object,'_realbinding'):
200
if parent._type == 'RpService':
202
object._realbinding=getattr(parent._realbinding,\
205
GDebug.printMesg(9,'* %s is bound to \n * %s' % \
206
(object._path,object._realbinding))
208
tmsg = u_("GNURPC cannot bind service '%(name)s' to service "
209
"'%(destination)s'") \
210
% {'name' : object.name,
211
'destination': parent.name}
212
raise AttributeError, tmsg
213
elif parent._type == 'RpGnuRpc':
216
tmsg = u_("GNURPC cannot bind service '%(name)s' to service "
217
"'%(destination)s'") \
218
% {'name' : object.name,
219
'destination': parent._type}
220
raise AttributeError, tmsg
222
# create binding for service
224
self.ns.deleteGroup(object._path)
228
self.ns.createGroup(object._path)
230
self._bindDelegateto(object._path+'.self',object._realbinding)
234
# Compute binding for methods and for attributs
235
# both are direct lins to the specific object
237
# the dispatcher has to distinguish methods and
238
# objects by testing if they are callable
239
if (object._type == 'RpMethod') or \
240
(object._type == 'RpAttribute'):
242
# check for the binding
243
if hasattr(object,'_realbinding'):
244
bindto=object._realbinding
246
if parent._type == 'RpService':
248
bindto=getattr(parent._realbinding,object.name)
249
GDebug.printMesg(9,'* %s is bound to \n * %s' % \
250
(object._path,bindto))
252
tmsg = u_("GNURPC cannot bind method/attribut '%(name)s' to "
253
"service '%(service)s'") \
254
% {'name' : object.name,
255
'service': parent.name}
256
raise AttributeError, tmsg
261
if object._type == 'RpMethod':
262
self.addRpMethod(object,parent,bindto)
265
# Add all attribute methods to our directory..
266
# XML-RPC doesn't support "Attributes", so an
267
# attribute is exposed as a pair of get_<name>
268
# and set_<name> methods.
270
if object._type == 'RpAttribute':
271
self.addRpAttribut(object,parent,bindto)
274
# Now, map our children
275
for child in object._children:
276
self.mapObjects(child, bindings, object)
278
def addRpMethod(self,object,parent,binding):
280
self._bindDelegateto(object._path,binding)
282
def _bindDelegateto(self,name,binding):
285
self.ns.unregister(name)
291
# register using delegation
292
proxy=Pyro.core.ObjBase()
293
proxy.delegateTo(binding)
294
#print 'bindto: %s (%s,%s)' % (name,binding, type(binding))
295
self.daemon.connect(proxy,name)
297
def addRpAttribut(self,object,parent,binding):
300
if not object.readonly:
301
# Add the set_* directory entry
302
self.daemon.connect({'%s.set_%s' % \
303
(parent._path, object.name):\
305
if not object.writeonly:
306
# Add the get_* directory entry
307
self.server.addMethods({'%s.get_%s' % \
308
(parent._path, object.name):\
312
# Call the requested method
314
def call(self, method, params):
316
print _("Dispatching: "), method, params
319
## Check if the Method is part of a service or a pointer to a
322
## Call to an object: method="_Management:235423456_.getAttr"
324
## Call to an method: (of a service=one object)
325
## method="DonutPlace.Management.Restart"
329
# 1. get the object from the objectlibrarian
330
# 2. check, if the object is supported by the gfd
332
i=string.index(method,']',1)
333
objhandle=method[1:i]
336
tmsg = u_("Wrong format of object handle in method call %s") % method
337
raise AttributeError, tmsg
338
# TODO check in service dir, if obj is supported or not
339
o=ObjectLibrarian.retrieveObject(objhandle)
341
server_method=getattr(o,method)
342
server_attribute=None
343
except AttributeError:
346
server_attribute=getattr(o,method[4:])
347
except AttributeError:
349
if method != "_close":
350
msg = u_("Internal XMLRPC server error: method %s can be "
351
"found in the directory (build out of a .grpc file), "
352
"but the object doesn't contain this method/attribut. "
353
"Please check you .grpc file for wrong return types.") \
356
raise AttributeError, msg
359
direntry = self.getMethodDirEntry(o._type+"."+method)
360
signature=direntry['signature']
362
signature= ('string',)
366
# call to a service method or a helper call (get/set) for
369
direntry = self.getMethodDirEntry(method)
370
server_method = direntry['binding']
371
server_attribute = None
373
# check if it is an real method (binding -> method)
374
# or an get/set method for an attribut (binding-> attribut)
375
if (type(server_method)!=type(self.call)):
376
server_attribute = server_method
379
signature=direntry['signature']
381
if (server_method==None) and (server_attribute==None):
382
tmsg = u_("Server XML-RPC method '%s' is not bound to real method") \
384
raise AttributeError, tmsg
386
tmsg = u_("Server does not have XML-RPC procedure %s") % method
387
raise AttributeError, tmsg
391
# TODO: Compare submitted attributs with signature
393
tmsg = u_("Server XML-RPC procedure %(method)s accepts just %(attr)s "
397
raise AttributeError, tmsg
400
# replace object handles in param with the real object
402
while counter<len(params):
404
if type(p)==type(""):
405
if (len(p)==42) and (p[0]=="[") and (p[41]=="]"):
408
obj=ObjectLibrarian.retrieveObject(p)
409
newp=params[0:counter-1]+(obj,)+params[counter+1:]
415
# check if it is an real method (binding -> method)
416
# or an get/set method for an attribut (binding-> attribut)
418
if (server_method!=None):
420
# call method with params
421
result=server_method(*params)
423
# check if it's the close object method
424
elif (method=="_close"):
426
result=self.releaseDynamicObject(o)
430
## check wether its the set or the get method for the attribut
431
mparts=string.splitfields(method,'.')
434
calltype=calltype[:4]
435
GDebug.printMesg(9,'method %s has calling type %s' %\
439
server_attribute=params[0]
440
elif calltype=='get_':
442
result=server_attribute
444
tmsg = u_("Internal Server XML-RPC error: method type (get/set "
445
"attribute) couldn't be detected (method %s)") % method
446
raise AttributeError, tmsg
449
# replace real object in param with an object handle
450
if type(result)==type(self): ## both should be instances
451
ObjectLibrarian.archiveObject(result)
453
# get the type of the result
455
# delete the surrounding brackets < >
456
rtype=rtype[1:len(rtype)-1]
457
# store typeinfo in new object
460
result=ObjectLibrarian.getObjectReference(result)
461
self.registerDynamicObject(result,rtype)
463
# check for empty results (not allowed for XMLRPC)
464
if (result==None) or (result==[None]):
465
GDebug.printMesg(9,'Transform result None into 1')
470
class RpcServiceProxy (Pyro.core.ObjBase):