| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
__authors__ = ["Sylvain Hellegouarch (sh@defuze.org)"] |
|---|
| 4 |
__version__ = "1.0" |
|---|
| 5 |
__date__ = "2005/11/04" |
|---|
| 6 |
__copyright__ = """ |
|---|
| 7 |
Copyright (c) 2005, Sylvain Hellegouarch |
|---|
| 8 |
All rights reserved. |
|---|
| 9 |
""" |
|---|
| 10 |
__license__ = """ |
|---|
| 11 |
Redistribution and use in source and binary forms, with or without modification, |
|---|
| 12 |
are permitted provided that the following conditions are met: |
|---|
| 13 |
|
|---|
| 14 |
* Redistributions of source code must retain the above copyright notice, |
|---|
| 15 |
this list of conditions and the following disclaimer. |
|---|
| 16 |
* Redistributions in binary form must reproduce the above copyright notice, |
|---|
| 17 |
this list of conditions and the following disclaimer in the documentation |
|---|
| 18 |
and/or other materials provided with the distribution. |
|---|
| 19 |
* Neither the name of Sylvain Hellegouarch nor the names of his contributors |
|---|
| 20 |
may be used to endorse or promote products derived from this software |
|---|
| 21 |
without specific prior written permission. |
|---|
| 22 |
|
|---|
| 23 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|---|
| 24 |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|---|
| 25 |
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|---|
| 26 |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
|---|
| 27 |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|---|
| 28 |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|---|
| 29 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|---|
| 30 |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|---|
| 31 |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|---|
| 32 |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 33 |
""" |
|---|
| 34 |
|
|---|
| 35 |
__doc__ = """ |
|---|
| 36 |
Defines some introspection function for a XML-RPC server application handled by CherryPy |
|---|
| 37 |
Please find at the bottom an example of this class |
|---|
| 38 |
""" |
|---|
| 39 |
|
|---|
| 40 |
import inspect |
|---|
| 41 |
import string |
|---|
| 42 |
|
|---|
| 43 |
class XmlRpcSystemInformation: |
|---|
| 44 |
""" |
|---|
| 45 |
Defines some introspection function for an XML-RPC server application handled by CherryPy |
|---|
| 46 |
See: http://docs.python.org/lib/serverproxy-objects.html |
|---|
| 47 |
|
|---|
| 48 |
""" |
|---|
| 49 |
def __init__(self): |
|---|
| 50 |
self.rpcmethods = {} |
|---|
| 51 |
|
|---|
| 52 |
def _cpOnError(self): |
|---|
| 53 |
|
|---|
| 54 |
|
|---|
| 55 |
import sys |
|---|
| 56 |
error_type = sys.exc_info()[0] |
|---|
| 57 |
if error_type in (LookupError, ValueError): |
|---|
| 58 |
return |
|---|
| 59 |
|
|---|
| 60 |
cherrypy.HTTPError(500).set_response() |
|---|
| 61 |
|
|---|
| 62 |
def register_class(self, classInstance, instancePath=None): |
|---|
| 63 |
""" |
|---|
| 64 |
Registers the given class exposed methods |
|---|
| 65 |
|
|---|
| 66 |
Keyword arguments: |
|---|
| 67 |
classInstance -- class instance which will be scanned for exposed methods |
|---|
| 68 |
instancePath -- sets the path to the instance (eg: obj1.obj2 for obj1.obj2.methodName) |
|---|
| 69 |
|
|---|
| 70 |
""" |
|---|
| 71 |
for method in inspect.getmembers(classInstance, inspect.ismethod): |
|---|
| 72 |
if getattr(method[1], 'exposed', False) == True: |
|---|
| 73 |
if instancePath: |
|---|
| 74 |
self.rpcmethods[instancePath + '.' + method[0]] = method[1] |
|---|
| 75 |
else: |
|---|
| 76 |
self.rpcmethods[method[0]] = method[1] |
|---|
| 77 |
|
|---|
| 78 |
def listMethods(self): |
|---|
| 79 |
""" |
|---|
| 80 |
Returns a list of all methods callable on the RPC server |
|---|
| 81 |
|
|---|
| 82 |
""" |
|---|
| 83 |
return self.rpcmethods.keys() |
|---|
| 84 |
listMethods.exposed = True |
|---|
| 85 |
|
|---|
| 86 |
def methodHelp(self, methodName): |
|---|
| 87 |
""" |
|---|
| 88 |
Returns the doc string of the method in parameter. |
|---|
| 89 |
If none available returns a default message. |
|---|
| 90 |
|
|---|
| 91 |
Keyword arguments: |
|---|
| 92 |
methodName -- name of the method to look up |
|---|
| 93 |
|
|---|
| 94 |
""" |
|---|
| 95 |
method = None |
|---|
| 96 |
if methodName not in self.rpcmethods.keys(): |
|---|
| 97 |
raise LookupError, "This method is not registered on this server" |
|---|
| 98 |
|
|---|
| 99 |
method = self.rpcmethods[methodName] |
|---|
| 100 |
|
|---|
| 101 |
doc = method.__doc__ |
|---|
| 102 |
if not doc: |
|---|
| 103 |
raise ValueError, 'No available help for ' + methodName |
|---|
| 104 |
return doc |
|---|
| 105 |
methodHelp.exposed = True |
|---|
| 106 |
|
|---|
| 107 |
if __name__ == '__main__': |
|---|
| 108 |
import cherrypy |
|---|
| 109 |
|
|---|
| 110 |
class A: |
|---|
| 111 |
def hello(self): |
|---|
| 112 |
return "hello there from A" |
|---|
| 113 |
hello.exposed = True |
|---|
| 114 |
|
|---|
| 115 |
class B: |
|---|
| 116 |
def hello(self): |
|---|
| 117 |
return "hello there from B" |
|---|
| 118 |
hello.exposed = True |
|---|
| 119 |
|
|---|
| 120 |
class Root: |
|---|
| 121 |
def echo(self, value=''): |
|---|
| 122 |
""" |
|---|
| 123 |
Return the value passed in parameters |
|---|
| 124 |
|
|---|
| 125 |
Keyword arguments: |
|---|
| 126 |
value -- the token to echo back (default '') |
|---|
| 127 |
|
|---|
| 128 |
""" |
|---|
| 129 |
return value |
|---|
| 130 |
echo.exposed = True |
|---|
| 131 |
|
|---|
| 132 |
|
|---|
| 133 |
cherrypy.root = Root() |
|---|
| 134 |
cherrypy.root.a = A() |
|---|
| 135 |
cherrypy.root.a.b = B() |
|---|
| 136 |
|
|---|
| 137 |
|
|---|
| 138 |
|
|---|
| 139 |
system = XmlRpcSystemInformation() |
|---|
| 140 |
system.register_class(cherrypy.root) |
|---|
| 141 |
system.register_class(cherrypy.root.a, 'a') |
|---|
| 142 |
system.register_class(cherrypy.root.a.b, 'a.b') |
|---|
| 143 |
|
|---|
| 144 |
cherrypy.root.system = system |
|---|
| 145 |
|
|---|
| 146 |
cherrypy.config.update({'global': { 'xmlRpcFilter.on':True, |
|---|
| 147 |
'server.socketPort': 8080 }}) |
|---|
| 148 |
|
|---|
| 149 |
cherrypy.server.start() |
|---|
| 150 |
|
|---|
| 151 |
|
|---|
| 152 |
|
|---|
| 153 |
|
|---|
| 154 |
|
|---|
| 155 |
|
|---|
| 156 |
|
|---|
| 157 |
|
|---|
| 158 |
|
|---|