This recipe shows how to build an xmlrpc multithread server that exposes a Pyro remote object as a web service. Be careful to the remote object state: two different ways (a global and a thread local) are shown.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | #########################################################
# The object (file object.py)
class myObject:
def __init__(self):
# a global counter
self.globalNumCalls = 0
def method1(self, string):
self.globalNumCalls += 1
return len(string)
def method2(self, number):
self.globalNumCalls += 1
return number*number
def getGlobalNumCalls(self):
return self.globalNumCalls
def remote_objects():
return { 'sampleObject': myObject() }
#########################################################
#########################################################
#########################################################
# The Pyro server, with a wrapper for object.myobject
# and thread local storage (file server.py)
import sys
import Pyro.core
import Pyro.naming
import object
class SampleObject(Pyro.core.ObjBase, object.myObject):
def __init__(self):
Pyro.core.ObjBase.__init__(self)
object.myObject.__init__(self)
def method2localcount(self, number):
# increment the thread-local counter
self.getLocalStorage().numSquareCalls += 1
# call the "standard" function (this will increment the global counter)
return self.method2(number)
def getNumLocalSquareCalls(self):
return self.getLocalStorage().numSquareCalls
def initTLS(tls):
print "Init TLS:",tls
print "Setting a counter, numSquareCalls, for this TLS to 0."
tls.numSquareCalls=0
if __name__ == "__main__":
Pyro.core.initServer()
daemon=Pyro.core.Daemon()
daemon.useNameServer(Pyro.naming.NameServerLocator().getNS())
daemon.setInitTLS(initTLS)
uri=daemon.connect(SampleObject(), "sampleObject")
print "sample object is running."
daemon.setTimeout(5)
daemon.requestLoop()
#########################################################
#########################################################
#########################################################
# The cherrypy server definition file (file testXmlRpc.cpy)
def initProgram():
import Pyro.core
def initThread(threadIndex):
time.sleep(threadIndex * 0.2)
# dispatch a pyro object to each thread via "request" reserved variable
Pyro.core.initClient()
request.x=Pyro.core.getProxyForURI("PYRONAME://sampleObject")
request.x._setTimeout(5)
request.x._release()
CherryClass Xml_rpc:
view:
def lenString(self, a) xmlrpc:
# Return the length of its input string
return request.x.method1(a)
def squareNumber(self, a) xmlrpc:
# Return the square of its input number
return request.x.method2(a)
def squareNumberLocalCount(self, a) xmlrpc:
# Return the square of its input number, incrementing a thread local counter, too.
return request.x.method2localcount(a)
def noglobalcalls(self) xmlrpc:
# Return the number of global calls
return request.x.getGlobalNumCalls()
def nosquarelocalcalls(self) xmlrpc:
# Return the number of thread-local calls
return request.x.getNumLocalSquareCalls()
#########################################################
#########################################################
#########################################################
# The cherrypy configuration file (file testXmlRpcServer.cfg)
[server]
typeOfRequests=xmlRpc,web
threadPool=3
#########################################################
#########################################################
#########################################################
# A sample test program (file testXmlRpcClient.py)
import xmlrpclib, time
testsvr = xmlrpclib.Server("http://localhost:8000")
sttime = time.time()
for i in xrange(1000):
assert len("I love cherry pie") == testsvr.xml.rpc.lenString("I love cherry pie")
assert testsvr.xml.rpc.squareNumber(12) == 144
print "# global calls:", testsvr.xml.rpc.noglobalcalls()
assert testsvr.xml.rpc.squareNumberLocalCount(6) == 36
print "# thread-local calls: ", testsvr.xml.rpc.nosquarelocalcalls()
print time.time() - sttime
#########################################################
#########################################################
|
It can happen to have to export a Pyro object as a web service: since the object is handled by means of it's server, working on the state of the object can be tricky, and one perhaps has to use Pyro thread-local storage. As reference, there's both Cherrypy and Pyro documentation.