2 # PLCAPI XML-RPC and SOAP interfaces
4 # Aaron Klingaman <alk@absarokasoft.com>
5 # Mark Huang <mlhuang@cs.princeton.edu>
7 # Copyright (C) 2004-2006 The Trustees of Princeton University
8 # $Id: API.py,v 1.4 2006/10/13 20:00:21 mlhuang Exp $
16 def dump(self, value, write):
18 xmlrpclib cannot marshal instances of subclasses of built-in
19 types. This function overrides xmlrpclib.Marshaller.__dump so that
20 any value that is an instance of one of its acceptable types is
21 marshalled as that type.
25 # Try for an exact match first
26 f = self.dispatch[type(value)]
28 # Try for an isinstance() match
29 for Type, f in self.dispatch.iteritems():
30 if isinstance(value, Type):
33 raise TypeError, "cannot marshal %s objects" % type(value)
37 # You can't hide from me!
38 xmlrpclib.Marshaller._Marshaller__dump = dump
40 # SOAP support is optional
43 from SOAPpy.Parser import parseSOAPRPC
44 from SOAPpy.Types import faultType
45 from SOAPpy.NS import NS
46 from SOAPpy.SOAPBuilder import buildSOAP
50 from PLC.Config import Config
51 from PLC.PostgreSQL import PostgreSQL
52 from PLC.Faults import *
56 methods = PLC.Methods.methods
58 def __init__(self, config = "/etc/planetlab/plc_config", encoding = "utf-8"):
59 self.encoding = encoding
61 # Better just be documenting the API
66 self.config = Config(config)
68 # Initialize database connection
69 if self.config.PLC_DB_TYPE == "postgresql":
70 self.db = PostgreSQL(self)
72 raise PLCAPIError, "Unsupported database type " + config.PLC_DB_TYPE
74 def callable(self, method):
76 Return a new instance of the specified method.
80 if method not in self.methods:
81 raise PLCInvalidAPIMethod, method
83 # Get new instance of method
85 classname = method.split(".")[-1]
86 module = __import__("PLC.Methods." + method, globals(), locals(), [classname])
87 return getattr(module, classname)(self)
88 except ImportError, AttributeError:
89 raise PLCInvalidAPIMethod, method
91 def call(self, source, method, *args):
93 Call the named method from the specified source with the
97 function = self.callable(method)
98 function.source = source
99 return function(*args)
101 def handle(self, source, data):
103 Handle an XML-RPC or SOAP request from the specified source.
106 # Parse request into method name and arguments
108 interface = xmlrpclib
109 (args, method) = xmlrpclib.loads(data)
110 methodresponse = True
112 if SOAPpy is not None:
114 (r, header, body, attrs) = parseSOAPRPC(data, header = 1, body = 1, attrs = 1)
117 # XXX Support named arguments
122 result = self.call(source, method, *args)
123 except PLCFault, fault:
124 # Handle expected faults
125 if interface == xmlrpclib:
127 methodresponse = None
128 elif interface == SOAPpy:
129 result = faultParameter(NS.ENV_T + ":Server", "Method Failed", method)
130 result._setDetail("Fault %d: %s" % (fault.faultCode, fault.faultString))
133 if interface == xmlrpclib:
134 if not isinstance(result, PLCFault):
136 data = xmlrpclib.dumps(result, methodresponse = True, encoding = self.encoding, allow_none = 1)
137 elif interface == SOAPpy:
138 data = buildSOAP(kw = {'%sResponse' % method: {'Result': result}}, encoding = self.encoding)