Back to index

nordugrid-arc-nox  1.1.0~rc6
pythonwrapper.cpp
Go to the documentation of this file.
00001 // based on:
00002 // http://www.codeproject.com/cpp/embedpython_1.asp
00003 // http://coding.derkeiler.com/Archive/Python/comp.lang.python/2006-11/msg01211.html
00004 #ifdef HAVE_CONFIG_H
00005 #include <config.h>
00006 #endif
00007 
00008 #include <iostream>
00009 #include <arc/message/SOAPMessage.h>
00010 #include <arc/message/PayloadSOAP.h>
00011 #include <arc/message/MCCLoader.h>
00012 #include <arc/Thread.h>
00013 #include "pythonwrapper.h"
00014 
00015 #ifndef WIN32
00016 #include <dlfcn.h>
00017 #endif
00018 
00019 #ifdef __cplusplus
00020 extern "C" {
00021 #endif
00022 
00023 /* SWIG Specific object SHOULD BE SYNC WITH generated SWIG CODE */
00024 typedef void *(*swig_converter_func)(void *);
00025 typedef struct swig_type_info *(*swig_dycast_func)(void **);
00026 
00027 typedef struct swig_type_info {
00028   const char             *name;         /* mangled name of this type */
00029   const char             *str;          /* human readable name of this type */
00030   swig_dycast_func        dcast;        /* dynamic cast function down a hierarchy */
00031   struct swig_cast_info  *cast;         /* linked list of types that can cast into this type */
00032   void                   *clientdata;   /* language specific type data */
00033   int                    owndata;       /* flag if the structure owns the clientdata */
00034 } swig_type_info;
00035 
00036 /* Structure to store a type and conversion function used for casting */
00037 typedef struct swig_cast_info {
00038   swig_type_info         *type;         /* pointer to type that is equivalent to this type */
00039   swig_converter_func     converter;    /* function to cast the void pointers */
00040   struct swig_cast_info  *next;         /* pointer to next cast in linked list */
00041   struct swig_cast_info  *prev;         /* pointer to the previous cast */
00042 } swig_cast_info;
00043 
00044 typedef struct {
00045   PyObject_HEAD
00046   void *ptr;
00047   swig_type_info *ty;
00048   int own;
00049   PyObject *next;
00050 } PySwigObject;
00051 
00052 #ifdef __cplusplus
00053 }
00054 #endif
00055 
00056 void *extract_swig_wrappered_pointer(PyObject *obj)
00057 {
00058     char this_str[] = "this";
00059     if (!PyObject_HasAttrString(obj, this_str)) {
00060         return NULL;
00061     }
00062     PyObject *thisAttr = PyObject_GetAttrString(obj, this_str);
00063     if (thisAttr == NULL) {
00064         return NULL;
00065     }
00066     void* ptr = ((PySwigObject *)thisAttr)->ptr;
00067     Py_DECREF(thisAttr);
00068     return ptr;
00069 }
00070 
00071 // Thread state of main python interpreter thread
00072 static PyThreadState *tstate = NULL;
00073 static int python_service_counter = 0;
00074 static Glib::Mutex service_lock;
00075 Arc::Logger Arc::Service_PythonWrapper::logger(RegisteredService::logger, "PythonWrapper");
00076 
00077 static Arc::Plugin* get_service(Arc::PluginArgument* arg) {
00078     Arc::ServicePluginArgument* srvarg =
00079             arg?dynamic_cast<Arc::ServicePluginArgument*>(arg):NULL;
00080     if(!srvarg) return NULL;
00081     Arc::ChainContext* ctx = (Arc::ChainContext*)(*srvarg);
00082 
00083 #ifndef WIN32
00084     // ((Arc::PluginsFactory*)(*ctx))->load("pythonservice",false,true); // doesn't work, why?
00085     ::dlopen(((Arc::PluginsFactory*)(*ctx))->findLocation("pythonservice").c_str(),RTLD_NOW | RTLD_GLOBAL);
00086 #endif
00087 
00088     service_lock.lock();
00089     // Initialize the Python Interpreter
00090     if (!Py_IsInitialized()) {
00091         Py_InitializeEx(0); // python does not handle signals
00092         PyEval_InitThreads(); // Main thread created and lock acquired
00093         tstate = PyThreadState_Get(); // Get current thread
00094         if(tstate == NULL) {
00095             Arc::Logger::getRootLogger().msg(Arc::ERROR, "Failed to initialize main Python thread");
00096             return NULL;
00097         }
00098     } else {
00099         if(tstate == NULL) {
00100             Arc::Logger::getRootLogger().msg(Arc::ERROR, "Main Python thread was not initialized");
00101             return NULL;
00102         }
00103         PyEval_AcquireThread(tstate);
00104     }
00105     python_service_counter++;
00106     Arc::Logger::getRootLogger().msg(Arc::DEBUG, "Loading %u-th Python service", python_service_counter);
00107     service_lock.unlock();
00108     Arc::RegisteredService* service = new Arc::Service_PythonWrapper((Arc::Config*)(*srvarg));
00109     PyEval_ReleaseThread(tstate); // Release current thread
00110     Arc::Logger::getRootLogger().msg(Arc::DEBUG, "Initialized %u-th Python service", python_service_counter);
00111     return service;
00112 }
00113 
00114 Arc::PluginDescriptor PLUGINS_TABLE_NAME[] = {
00115     { "pythonservice", "HED:SERVICE", 0, &get_service },
00116     { NULL, NULL, 0, NULL }
00117 };
00118 
00119 namespace Arc {
00120 
00121 Service_PythonWrapper::Service_PythonWrapper(Arc::Config *cfg):RegisteredService(cfg)
00122 {
00123     PyObject *py_module_name = NULL;
00124     PyObject *py_arc_module_name = NULL;
00125     PyObject *dict = NULL;
00126     PyObject *arc_dict = NULL;
00127     PyObject *arc_cfg_klass = NULL;
00128     PyObject *arg = NULL;
00129     PyObject *py_cfg = NULL;
00130     PyObject *klass = NULL;
00131 
00132     arc_module = NULL;
00133     module = NULL;
00134     object = NULL;
00135     initialized = false;
00136 
00137     if (tstate == NULL) {
00138         logger.msg(Arc::ERROR, "Main python thread is not initialized");
00139         return;
00140     }
00141     //PyEval_AcquireThread(tstate);
00142 
00143     std::string path = (std::string)(*cfg)["ClassName"];
00144     std::size_t p = path.rfind(".");
00145     if (p == std::string::npos) {
00146         logger.msg(Arc::ERROR, "Invalid class name");
00147         return;
00148     }
00149     std::string module_name = path.substr(0, p);
00150     std::string class_name = path.substr(p+1, path.length());
00151     logger.msg(Arc::VERBOSE, "class name: %s", class_name);
00152     logger.msg(Arc::VERBOSE, "module name: %s", module_name);
00153 
00154     // Convert module name to Python string
00155     py_module_name = PyString_FromString(module_name.c_str());
00156     if (py_module_name == NULL) {
00157         logger.msg(Arc::ERROR, "Cannot convert module name to Python string");
00158         if (PyErr_Occurred()) PyErr_Print();
00159         return;
00160     }
00161     // Load module
00162     module = PyImport_Import(py_module_name);
00163     if (module == NULL) {
00164         logger.msg(Arc::ERROR, "Cannot import module");
00165         if (PyErr_Occurred()) PyErr_Print();
00166         Py_DECREF(py_module_name);
00167         return;
00168     }
00169     Py_DECREF(py_module_name);
00170 
00171     // Import ARC python wrapper
00172     py_arc_module_name = PyString_FromString("arc");
00173     if (py_arc_module_name == NULL) {
00174         logger.msg(Arc::ERROR, "Cannot convert arc module name to Python string");
00175         if (PyErr_Occurred()) PyErr_Print();
00176         return;
00177     }
00178 
00179     // Load arc module
00180     arc_module = PyImport_Import(py_arc_module_name);
00181     if (arc_module == NULL) {
00182         logger.msg(Arc::ERROR, "Cannot import arc module");
00183         if (PyErr_Occurred()) PyErr_Print();
00184         Py_DECREF(py_arc_module_name);
00185         return;
00186     }
00187     Py_DECREF(py_arc_module_name);
00188 
00189     // arc_dict is a borrowed reference
00190     arc_dict = PyModule_GetDict(arc_module);
00191     if (arc_dict == NULL) {
00192         logger.msg(Arc::ERROR, "Cannot get dictionary of arc module");
00193         if (PyErr_Occurred()) PyErr_Print();
00194         return;
00195     }
00196 
00197     // Get the arc config class
00198     // arc_cfg_klass is a borrowed reference
00199     arc_cfg_klass = PyDict_GetItemString(arc_dict, "Config");
00200     if (arc_cfg_klass == NULL) {
00201         logger.msg(Arc::ERROR, "Cannot find arc Config class");
00202         if (PyErr_Occurred()) PyErr_Print();
00203         return;
00204     }
00205 
00206     // check is it really a class
00207     if (!PyCallable_Check(arc_cfg_klass)) {
00208         logger.msg(Arc::ERROR, "Config klass is not an object");
00209         return;
00210     }
00211 
00212     // Get dictionary of module content
00213     // dict is a borrowed reference
00214     dict = PyModule_GetDict(module);
00215     if (dict == NULL) {
00216         logger.msg(Arc::ERROR, "Cannot get dictionary of module");
00217         if (PyErr_Occurred()) PyErr_Print();
00218         return;
00219     }
00220 
00221     // Get the class
00222     // klass is a borrowed reference
00223     klass = PyDict_GetItemString(dict, (char*)class_name.c_str());
00224     if (klass == NULL) {
00225         logger.msg(Arc::ERROR, "Cannot find service class");
00226         if (PyErr_Occurred()) PyErr_Print();
00227         return;
00228     }
00229 
00230     // check is it really a class
00231     if (PyCallable_Check(klass)) {
00232         arg = Py_BuildValue("(l)", (long int)cfg);
00233         if (arg == NULL) {
00234             logger.msg(Arc::ERROR, "Cannot create config argument");
00235             if (PyErr_Occurred()) PyErr_Print();
00236             return;
00237         }
00238 
00239         py_cfg = PyObject_CallObject(arc_cfg_klass, arg);
00240         if (py_cfg == NULL) {
00241             logger.msg(Arc::ERROR, "Cannot convert config to python object");
00242             if (PyErr_Occurred()) PyErr_Print();
00243             Py_DECREF(arg);
00244             return;
00245         }
00246         Py_DECREF(arg);
00247         arg = Py_BuildValue("(O)", py_cfg);
00248         if (arg == NULL) {
00249             logger.msg(Arc::ERROR, "Cannot create argument of the constructor");
00250             if (PyErr_Occurred()) PyErr_Print();
00251             return;
00252         }
00253 
00254         // create instance of class
00255         object = PyObject_CallObject(klass, arg);
00256         if (object == NULL) {
00257             logger.msg(Arc::ERROR, "Cannot create instance of python class");
00258             if (PyErr_Occurred()) PyErr_Print();
00259             return;
00260         }
00261         Py_DECREF(arg);
00262 
00263     } else {
00264         logger.msg(Arc::ERROR, "%s is not an object", class_name);
00265         return;
00266     }
00267 
00268     // check is it really a class
00269     if (!PyCallable_Check(klass)) {
00270         logger.msg(Arc::ERROR, "Message klass is not an object");
00271         return;
00272     }
00273     //tstate = PyGILState_GetThisThreadState();
00274     //PyEval_ReleaseThread(tstate);
00275 
00276     logger.msg(Arc::VERBOSE, "Python Wrapper constructor succeeded");
00277     initialized = true;
00278 }
00279 
00280 Service_PythonWrapper::~Service_PythonWrapper(void)
00281 {
00282     service_lock.lock();
00283     PyEval_AcquireThread(tstate);
00284     // Release python objects - it is needed for Python
00285     // destructors to be called
00286     if(arc_module) Py_DECREF(arc_module);
00287     if(module) Py_DECREF(module);
00288     if(object) Py_DECREF(object);
00289     // Finish the Python Interpreter
00290     python_service_counter--;
00291     logger.msg(Arc::VERBOSE, "Python Wrapper destructor (%d)", python_service_counter);
00292     if (python_service_counter == 0) {
00293         Py_Finalize();
00294     } else {
00295         PyEval_ReleaseThread(tstate);
00296     }
00297     service_lock.unlock();
00298 }
00299 
00300 Arc::MCC_Status Service_PythonWrapper::make_fault(Arc::Message& outmsg)
00301 {
00302     Arc::PayloadSOAP* outpayload = new Arc::PayloadSOAP(Arc::NS(),true);
00303     Arc::SOAPFault* fault = outpayload->Fault();
00304     if(fault) {
00305         fault->Code(Arc::SOAPFault::Sender);
00306         fault->Reason("Failed processing request");
00307     };
00308     outmsg.Payload(outpayload);
00309     return Arc::MCC_Status();
00310 }
00311 
00312 /*
00313 Arc::MCC_Status Service_PythonWrapper::python_error(const char *str) {
00314     return Arc::MCC_Status(Arc::GENERIC_ERROR);
00315 }*/
00316 
00317 class PythonLock {
00318   private:
00319     PyGILState_STATE gstate_;
00320     Arc::Logger& logger_;
00321   public:
00322     PythonLock(Arc::Logger& logger):logger_(logger) {
00323         gstate_ = PyGILState_Ensure();
00324         logger_.msg(Arc::VERBOSE, "Python interpreter locked");
00325     };
00326     ~PythonLock(void) {
00327         PyGILState_Release(gstate_);
00328         logger_.msg(Arc::VERBOSE, "Python interpreter released");
00329     };
00330 };
00331 
00332 class XMLNodeP {
00333   private:
00334     Arc::XMLNode* obj_;
00335   public:
00336     XMLNodeP(Arc::XMLNode& node):obj_(NULL) {
00337         try {
00338             obj_ = new Arc::XMLNode(node);
00339         } catch(std::exception& e) { };
00340     };
00341     ~XMLNodeP(void) {
00342         if(obj_) delete obj_;
00343     };
00344     XMLNode& operator*(void) const { return *obj_; };
00345     XMLNode* operator->(void) const { return obj_; };
00346     operator bool(void) { return (obj_ != NULL); };
00347     bool operator!(void) { return (obj_ == NULL); };
00348     operator long int(void) { return (long int)obj_; };
00349 };
00350 
00351 class SOAPMessageP {
00352   private:
00353     Arc::SOAPMessage* obj_;
00354   public:
00355     SOAPMessageP(Arc::Message& msg):obj_(NULL) {
00356         try {
00357             obj_ = new Arc::SOAPMessage(msg);
00358         } catch(std::exception& e) { };
00359     };
00360     ~SOAPMessageP(void) {
00361         if(obj_) delete obj_;
00362     };
00363     SOAPMessage& operator*(void) const { return *obj_; };
00364     SOAPMessage* operator->(void) const { return obj_; };
00365     operator bool(void) { return (obj_ != NULL); };
00366     bool operator!(void) { return (obj_ == NULL); };
00367     operator long int(void) { return (long int)obj_; };
00368 };
00369 
00370 class PyObjectP {
00371   private:
00372     PyObject* obj_;
00373   public:
00374     PyObjectP(PyObject* obj):obj_(obj) { };
00375     ~PyObjectP(void) { if(obj_) Py_DECREF(obj_); };
00376     operator bool(void) { return (obj_ != NULL); };
00377     bool operator!(void) { return (obj_ == NULL); };
00378     operator PyObject*(void) { return obj_; };
00379 };
00380 
00381 Arc::MCC_Status Service_PythonWrapper::process(Arc::Message& inmsg, Arc::Message& outmsg)
00382 {
00383     //PyObject *py_status = NULL;
00384     //PyObject *py_inmsg = NULL;
00385     //PyObject *py_outmsg = NULL;
00386     PyObject *arg = NULL;
00387 
00388     logger.msg(Arc::VERBOSE, "Python wrapper process called");
00389 
00390     if(!initialized) return Arc::MCC_Status();
00391 
00392     PythonLock plock(logger);
00393 
00394     // Convert in message to SOAP message
00395     Arc::SOAPMessageP inmsg_ptr(inmsg);
00396     if(!inmsg_ptr) {
00397         logger.msg(Arc::ERROR, "Failed to create input SOAP container");
00398         return make_fault(outmsg);
00399     }
00400     if(!inmsg_ptr->Payload()) {
00401         logger.msg(Arc::ERROR, "input is not SOAP");
00402         return make_fault(outmsg);
00403     }
00404     // Convert incomming message to python object
00405     arg = Py_BuildValue("(l)", (long int)inmsg_ptr);
00406     if (arg == NULL) {
00407         logger.msg(Arc::ERROR, "Cannot create inmsg argument");
00408         if (PyErr_Occurred()) PyErr_Print();
00409         return make_fault(outmsg);
00410     }
00411     // arc_dict is a borrowed reference
00412     PyObject *arc_dict = PyModule_GetDict(arc_module);
00413     if (arc_dict == NULL) {
00414         logger.msg(Arc::ERROR, "Cannot get dictionary of arc module");
00415         if (PyErr_Occurred()) PyErr_Print();
00416         return make_fault(outmsg);
00417     }
00418     // arc_msg_klass is a borrowed reference
00419     PyObject *arc_msg_klass = PyDict_GetItemString(arc_dict, "SOAPMessage");
00420     if (arc_msg_klass == NULL) {
00421         logger.msg(Arc::ERROR, "Cannot find arc Message class");
00422         if (PyErr_Occurred()) PyErr_Print();
00423         return make_fault(outmsg);
00424     }
00425     PyObjectP py_inmsg(PyObject_CallObject(arc_msg_klass, arg));
00426     if (!py_inmsg) {
00427         logger.msg(Arc::ERROR, "Cannot convert inmsg to python object");
00428         if (PyErr_Occurred()) PyErr_Print();
00429         Py_DECREF(arg);
00430         return make_fault(outmsg);
00431     }
00432     Py_DECREF(arg);
00433 
00434     Arc::SOAPMessageP outmsg_ptr(outmsg);
00435     if(!outmsg_ptr) {
00436         logger.msg(Arc::ERROR, "Failed to create SOAP containers");
00437         return make_fault(outmsg);
00438     }
00439     // Convert incomming and outcoming messages to python objects
00440     arg = Py_BuildValue("(l)", (long int)outmsg_ptr);
00441     if (arg == NULL) {
00442         logger.msg(Arc::ERROR, "Cannot create outmsg argument");
00443         if (PyErr_Occurred()) PyErr_Print();
00444         return make_fault(outmsg);
00445     }
00446     PyObjectP py_outmsg = PyObject_CallObject(arc_msg_klass, arg);
00447     if (!py_outmsg) {
00448         logger.msg(Arc::ERROR, "Cannot convert outmsg to python object");
00449         if (PyErr_Occurred()) PyErr_Print();
00450         Py_DECREF(arg);
00451         return make_fault(outmsg);
00452     }
00453     Py_DECREF(arg);
00454 
00455     // Call the process method
00456     PyObjectP py_status(PyObject_CallMethod(object, (char*)"process", (char*)"(OO)",
00457                                     (PyObject*)py_inmsg, (PyObject*)py_outmsg));
00458     if (!py_status) {
00459         if (PyErr_Occurred()) PyErr_Print();
00460         return make_fault(outmsg);
00461     }
00462 
00463     MCC_Status *status_ptr2 = (MCC_Status *)extract_swig_wrappered_pointer(py_status);
00464     Arc::MCC_Status status;
00465     if(status_ptr2) status=(*status_ptr2);
00466     {
00467         // std::string str = (std::string)status;
00468         // std::cout << "status: " << str << std::endl;
00469     };
00470     SOAPMessage *outmsg_ptr2 = (SOAPMessage *)extract_swig_wrappered_pointer(py_outmsg);
00471     if(outmsg_ptr2 == NULL) return make_fault(outmsg);
00472     SOAPEnvelope *p = outmsg_ptr2->Payload();
00473     if(p == NULL) return make_fault(outmsg);
00474     {
00475         // std::string xml;
00476         // if(p) p->GetXML(xml);
00477         // std::cout << "XML: " << xml << std::endl;
00478     };
00479 
00480     Arc::PayloadSOAP *pl = new Arc::PayloadSOAP(*p);
00481     {
00482         // std::string xml;
00483         // pl->GetXML(xml);
00484         // std::cout << "XML: " << xml << std::endl;
00485     };
00486 
00487     outmsg.Payload(pl);
00488     return status;
00489 }
00490 
00491 bool Service_PythonWrapper::RegistrationCollector(Arc::XMLNode& doc) {
00492     PyObject *arg = NULL;
00493 
00494     // logger.msg(Arc::VERBOSE, "Python 'RegistrationCollector' wrapper process called");
00495 
00496     if(!initialized) return false;
00497 
00498     PythonLock plock(logger);
00499 
00500     // Convert doc to XMLNodeP
00501     // logger.msg(Arc::VERBOSE, "Convert doc to XMLNodeP");
00502     Arc::XMLNodeP doc_ptr(doc);
00503     if (!doc_ptr) {
00504         logger.msg(Arc::ERROR, "Failed to create XMLNode container");
00505         return false;
00506     }
00507 
00508     // Convert doc to python object
00509     // logger.msg(Arc::VERBOSE, "Convert doc to python object");
00510     // logger.msg(Arc::VERBOSE, "Create python XMLNode");
00511     // arc_dict is a borrowed reference
00512     PyObject *arc_dict = PyModule_GetDict(arc_module);
00513     if (arc_dict == NULL) {
00514         logger.msg(Arc::ERROR, "Cannot get dictionary of arc module");
00515         if (PyErr_Occurred()) PyErr_Print();
00516         return false;
00517     }
00518     // arc_xmlnode_klass is a borrowed reference
00519     PyObject *arc_xmlnode_klass = PyDict_GetItemString(arc_dict, "XMLNode");
00520     if (arc_xmlnode_klass == NULL) {
00521         logger.msg(Arc::ERROR, "Cannot find arc XMLNode class");
00522         if (PyErr_Occurred()) PyErr_Print();
00523         return false;
00524     }
00525     arg = Py_BuildValue("(l)", (long int)doc_ptr);
00526     if (arg == NULL) {
00527         logger.msg(Arc::ERROR, "Cannot create doc argument");
00528         if (PyErr_Occurred()) PyErr_Print();
00529         return false;
00530     }
00531     PyObjectP py_doc(PyObject_CallObject(arc_xmlnode_klass, arg));
00532         if (!py_doc) {
00533         logger.msg(Arc::ERROR, "Cannot convert doc to python object");
00534         if (PyErr_Occurred()) PyErr_Print();
00535         Py_DECREF(arg);
00536         return false;
00537     }
00538     Py_DECREF(arg);
00539 
00540     // Call the RegistrationCollector method
00541     // logger.msg(Arc::VERBOSE, "Call the RegistrationCollector method");
00542     PyObjectP py_bool(PyObject_CallMethod(object, (char*)"RegistrationCollector", (char*)"(O)",
00543                       (PyObject*)py_doc));
00544 
00545     if (!py_bool) {
00546         if (PyErr_Occurred()) PyErr_Print();
00547         return false;
00548     }
00549 
00550     // Convert the return value of the function back to cpp
00551     // logger.msg(Arc::VERBOSE, "Convert the return value of the function back to cpp");
00552     bool *ret_val2 = (bool *)extract_swig_wrappered_pointer(py_bool);
00553     bool return_value = false;
00554     if (ret_val2) return_value = (*ret_val2);
00555 
00556     XMLNode *doc2 = (XMLNode *)extract_swig_wrappered_pointer(py_doc);
00557     if (doc2 == NULL) return false;
00558     (*doc2).New(doc);
00559     return true;
00560 }
00561 
00562 } // namespace Arc
00563