Initial checkin of new API implementation
[plcapi.git] / PLC / API.py
1 #
2 # PLCAPI XML-RPC and SOAP interfaces
3 #
4 # Aaron Klingaman <alk@absarokasoft.com>
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 #
7 # Copyright (C) 2004-2006 The Trustees of Princeton University
8 # $Id$
9 #
10
11 import sys
12 import traceback
13
14 import xmlrpclib
15
16 import SOAPpy
17 from SOAPpy.Parser import parseSOAPRPC
18 from SOAPpy.Types import faultType
19 from SOAPpy.NS import NS
20 from SOAPpy.SOAPBuilder import buildSOAP
21
22 from PLC.Config import Config
23 from PLC.PostgreSQL import PostgreSQL
24 from PLC.Faults import *
25 import PLC.Methods
26
27 class PLCAPI:
28     methods = PLC.Methods.methods
29
30     def __init__(self, config = "/etc/planetlab/plc_config"):
31         # Better just be documenting the API
32         if config is None:
33             return
34
35         # Load configuration
36         self.config = Config(config)
37
38         # Initialize database connection
39         if self.config.PLC_DB_TYPE == "postgresql":
40             self.db = PostgreSQL(self)
41         else:
42             raise PLCAPIError, "Unsupported database type " + config.PLC_DB_TYPE
43
44     def callable(self, method):
45         """
46         Return a new instance of the specified method.
47         """
48
49         # Look up method
50         if method not in self.methods:
51             raise PLCInvalidAPIMethod, method
52
53         # Get new instance of method
54         try:
55             classname = method.split(".")[-1]
56             module = __import__("PLC.Methods." + method, globals(), locals(), [classname])
57             return getattr(module, classname)(self)
58         except ImportError, AttributeError:
59             raise PLCInvalidAPIMethod, method
60
61     def call(self, source, method, *args):
62         """
63         Call the named method from the specified source with the
64         specified arguments.
65         """
66
67         function = self.callable(method)
68         function.source = source
69         return function(*args)
70
71     def handle(self, source, data):
72         """
73         Handle an XML-RPC or SOAP request from the specified source.
74         """
75
76         # Parse request into method name and arguments
77         try:
78             interface = xmlrpclib
79             (args, method) = xmlrpclib.loads(data)
80             methodresponse = True
81         except:
82             interface = SOAPpy
83             (r, header, body, attrs) = parseSOAPRPC(data, header = 1, body = 1, attrs = 1)
84             method = r._name
85             args = r._aslist()
86             # XXX Support named arguments
87
88         try:
89             result = self.call(source, method, *args)
90         except PLCFault, fault:
91             # Handle expected faults
92             if interface == xmlrpclib:
93                 result = fault
94                 methodresponse = None
95             elif interface == SOAPpy:
96                 result = faultParameter(NS.ENV_T + ":Server", "Method Failed", method)
97                 result._setDetail("Fault %d: %s" % (fault.faultCode, fault.faultString))
98
99         # Return result
100         if interface == xmlrpclib:
101             if not isinstance(result, PLCFault):
102                 result = (result,)
103             data = xmlrpclib.dumps(result, methodresponse = True)
104         elif interface == SOAPpy:
105             data = buildSOAP(kw = {'%sResponse' % method: {'Result': result}})
106
107         return data