diff options
Diffstat (limited to 'sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/sca_module.cpp')
-rw-r--r-- | sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/sca_module.cpp | 540 |
1 files changed, 540 insertions, 0 deletions
diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/sca_module.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/sca_module.cpp new file mode 100644 index 0000000000..dc2c7bfe22 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/sca_module.cpp @@ -0,0 +1,540 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#include <string> +#include <iostream> +#include <sstream> + +// undefine _DEBUG so Python does not need it's debug dll +#ifdef _DEBUG +#undef _DEBUG +#define _SCA_PYTHON_DEBUG +#endif +#include <Python.h> +#ifdef _SCA_PYTHON_DEBUG +#define _DEBUG +#endif + +#include "commonj/sdo/SDO.h" + +#include "PythonServiceProxy.h" +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/core/Exceptions.h" +#include "tuscany/sca/core/SCARuntime.h" +#include "tuscany/sca/model/Component.h" +#include "tuscany/sca/model/Reference.h" +#include "tuscany/sca/model/ReferenceType.h" +#include "tuscany/sca/model/ServiceBinding.h" +#include "tuscany/sca/core/Operation.h" + +using namespace std; +using namespace commonj::sdo; +using namespace tuscany::sca; +using namespace tuscany::sca::model; + +static PyObject* scaError; + +/** +* Prints out PyObject and dir(PyObject) +* for debugging purposes +*/ +static void printPyObject(char* prefix, char* name, PyObject* pObj) +{ + PyObject* pObjRepr = PyObject_Repr(pObj); + PyTypeObject* type = pObj->ob_type; + loginfo("%s printPyObject (%s) %s = %s", prefix, type->tp_name, name, PyString_AsString(pObjRepr)); + Py_XDECREF(pObjRepr); + + if(pObj != NULL) + { + PyObject* pObjDir = PyObject_Dir(pObj); + PyObject* pObjDirRepr = PyObject_Repr(pObjDir); + loginfo("%s printPyObject dir(%s): %s", prefix, name, PyString_AsString(pObjDirRepr)); + Py_DECREF(pObjDirRepr); + Py_DECREF(pObjDir); + } +} + +static PyObject* sca_locateservice(PyObject *self, PyObject *args) +{ + logentry(); + + // Get the service name + PyObject* pServiceName = PyTuple_GetItem(args, 0); + + // Import the SCA python-extension module + PyObject* pModuleName = PyString_FromString("sca_proxy"); + PyObject* sca_proxy_module = PyImport_Import(pModuleName); + Py_DECREF(pModuleName); + + if(!sca_proxy_module) + { + if(PyErr_Occurred()) + { + PyErr_Print(); + } + string msg = "Failed to load the sca_proxy Python module - has it been successfully installed?\nReferences from Python components will not be supported"; + logerror(msg.c_str()); + } + else + { + // Get the sca_proxy class + PyObject* sca_proxy_class = PyObject_GetAttrString(sca_proxy_module, "sca_proxy_class"); + + PyObject* scaArgs = PyTuple_New(2); + PyTuple_SetItem(scaArgs, 0, pServiceName); + Py_INCREF(Py_True); + PyTuple_SetItem(scaArgs, 1, Py_False); + + // Create the instance of the scaReference class + PyObject* sca_proxy_classInstance = PyInstance_New(sca_proxy_class, scaArgs, NULL); + Py_DECREF(scaArgs); + + return sca_proxy_classInstance; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static tuscany::sca::python::PythonServiceProxy* getServiceProxy(PyObject *args) +{ + logentry(); + + tuscany::sca::python::PythonServiceProxy* serviceProxy = NULL; + SCARuntime* runtime = SCARuntime::getCurrentRuntime(); + + // The first argument holds the name + string name; + PyObject* pName = PyTuple_GetItem(args, 0); + if(pName && PyString_Check(pName)) + { + name = PyString_AsString(pName); + } + if(name.size() > 0) + { + loginfo("Service/Reference name is %s", name.c_str()); + } + else + { + string msg = "Service/Reference name has not been set"; + logwarning(msg.c_str()); + PyErr_SetString(scaError, msg.c_str()); + return NULL; + } + + // The second argument is a boolean + PyObject* isReference = PyTuple_GetItem(args, 1); + + // Get the serviceProxy from the reference or service name provided + if(PyObject_IsTrue(isReference)) + { + Component* component = runtime->getCurrentComponent(); + Reference* ref = component->findReference(name); + if(!ref) + { + string msg = "Could not find the reference: "+name; + logwarning(msg.c_str()); + PyErr_SetString(scaError, msg.c_str()); + + return NULL; + } + + ReferenceBinding* refBinding = ref->getBinding(); + serviceProxy = (tuscany::sca::python::PythonServiceProxy*) refBinding->getServiceProxy(); + } + else + { + Component* component = runtime->getDefaultComponent(); + Composite* composite = (Composite*)component->getType(); + Service* service = composite->findComponentService(name); + + if(!service) + { + string msg = "Could not find service: "+name; + logwarning(msg.c_str()); + PyErr_SetString(scaError, msg.c_str()); + return NULL; + } + + serviceProxy = new tuscany::sca::python::PythonServiceProxy(service); + } + + return serviceProxy; +} + + +static PyObject* sca_invoke(PyObject *self, PyObject *args) +{ + logentry(); + + tuscany::sca::python::PythonServiceProxy* pythonServiceProxy = getServiceProxy(args); + if(!pythonServiceProxy) + { + return NULL; + } + + // Get the component from the reference or service provided + Component* component = NULL; + SCARuntime* runtime = SCARuntime::getCurrentRuntime(); + + PyObject* isReference = PyTuple_GetItem(args, 1); + if(PyObject_IsTrue(isReference)) + { + component = runtime->getCurrentComponent(); + } + else + { + component = runtime->getDefaultComponent(); + } + + // Get the name of the operation to invoke + string operationName; + PyObject* opName = PyTuple_GetItem(args, 2); + if(opName && PyString_Check(opName)) + { + operationName = PyString_AsString(opName); + } + + if(operationName.size() > 0) + { + loginfo("sca_invoke Operation name: %s", operationName.c_str()); + } + else + { + string msg = "Operation name has not been set"; + logwarning(msg.c_str()); + PyErr_SetString(scaError, msg.c_str()); + return NULL; + } + + // Create the Operation object + Operation operation(operationName.c_str()); + + // Load up the xml.etree.ElementTree module for dealing with SDO params and return values + PyObject* elementTreeModuleName = PyString_FromString("xml.etree.ElementTree"); + PyObject* elementTreeModule = PyImport_Import(elementTreeModuleName); + + if(elementTreeModule == NULL) + { + // pre-Python2.5? - try to get an installed elementtree package + elementTreeModuleName = PyString_FromString("elementtree.ElementTree"); + elementTreeModule = PyImport_Import(elementTreeModuleName); + } + if(elementTreeModule == NULL) + { + // Still null - throw a warning but carry on - user may not need XML + logwarning("Could not load Python ElementTree module - is it installed? SDO and XML will not be supported"); + } + + // Parameters are the fourth argument + PyObject* paramTuple = PyTuple_GetItem(args, 3); + unsigned int numberOfArgs = (unsigned int) PyTuple_Size(paramTuple); + loginfo("sca_invoke %d arg parameters supplied", numberOfArgs); + + // Keyword parameters (AKA named arguments) are the fifth argument + PyObject* keywordParamDict = PyTuple_GetItem(args, 4); + loginfo("sca_invoke %d keyword parameters supplied", PyDict_Size(keywordParamDict)); + + PyObject* paramKeys = PyDict_Keys(keywordParamDict); + + // Go through all the supplied parameters (args and keyword args) + for(unsigned int i=0; i < (numberOfArgs + PyList_Size(paramKeys)); i++) + { + string* paramName; + PyObject* param; + + if(i < PyTuple_Size(paramTuple)) + { + param = PyTuple_GetItem(paramTuple, i); + paramName = new string(); + } + else + { + PyObject* key = PyList_GetItem(paramKeys, i-numberOfArgs); + param = PyDict_GetItem(keywordParamDict, key); + paramName = new string(PyString_AsString(key)); + } + + if(PyInt_Check(param)) + { + loginfo("Int param %d %s: %d", i, (*paramName).c_str(), PyInt_AsLong(param)); + long* intData = new long; + *intData = PyInt_AsLong(param); + operation.addParameter(*paramName, intData); + } + else if(PyBool_Check(param)) + { + loginfo("Bool param %d %s: %d", i, (*paramName).c_str(), (param == Py_True)); + bool* boolData = new bool; + *boolData = (param == Py_True); + operation.addParameter(*paramName, boolData); + } + else if(PyLong_Check(param)) + { + loginfo("Long param %d %s: %l", i, (*paramName).c_str(), PyLong_AsLong(param)); + long* longData = new long; + *longData = PyLong_AsLong(param); + operation.addParameter(*paramName, longData); + } + else if(PyFloat_Check(param)) + { + loginfo("Float param %d %s: %f", i, (*paramName).c_str(), PyFloat_AsDouble(param)); + double* doubleData = new double; + *doubleData = PyFloat_AsDouble(param); + operation.addParameter(*paramName, doubleData); + } + else if(PyString_Check(param)) + { + loginfo("String param %d %s: %s", i, (*paramName).c_str(), PyString_AsString(param)); + const char** stringData = new const char*; + *stringData = PyString_AsString(param); + operation.addParameter(*paramName, stringData); + } + else + { + PyObject* pIsElement = Py_False; + if(elementTreeModule != NULL) + { + // Get the xml.etree.ElementTree.iselement function + PyObject* elementTreeIsElementFunc = PyObject_GetAttrString(elementTreeModule, "iselement"); + + // Call the iselement() function with pValue to check it + pIsElement = PyObject_CallFunction(elementTreeIsElementFunc, "O", param); + } + + if(PyObject_IsTrue(pIsElement) == 1) + { + // pValue is an xml.etree.ElementTree.Element - convert to SDO + PyObject* elementTreeToStringFunc = PyObject_GetAttrString(elementTreeModule, "tostring"); + PyObject* pElemString = PyObject_CallFunction(elementTreeToStringFunc, "O", param); + char* data = PyString_AsString(pElemString); + loginfo("SDO param %d %s: %s", i, (*paramName).c_str(), data); + + loginfo("Converting Python ElementTree to SDO DataObject: %s", data); + + Composite* composite = component->getComposite(); + XMLHelperPtr xmlHelper = composite->getXMLHelper(); + XMLDocumentPtr xmlDoc = xmlHelper->load(data); + + DataObjectPtr* dataObjectData = new DataObjectPtr; + if (xmlDoc != NULL) + { + *dataObjectData = xmlDoc->getRootDataObject(); + } + else + { + *dataObjectData = NULL; + } + if (*dataObjectData != NULL) + { + operation.addParameter(*paramName, dataObjectData); + } + else + { + string msg = "xml.etree.ElementTree.Element could not be converted to a DataObject"; + logerror(msg.c_str()); + PyErr_SetString(scaError, msg.c_str()); + return NULL; + } + Py_DECREF(elementTreeToStringFunc); + Py_DECREF(pElemString); + } + else + { + + PyObject* paramRepr = PyObject_Repr(param); + PyObject* paramType = PyObject_Type(param); + PyObject* paramTypeRepr = PyObject_Repr(paramType); + + string msg = "sca_invoke Param "; + msg += i; + msg += "is of unknown type ("; + msg += PyString_AsString(paramTypeRepr); + msg += ") and has repr: "; + msg += PyString_AsString(paramRepr); + + logerror(msg.c_str()); + PyErr_SetString(scaError, msg.c_str()); + + Py_DECREF(paramTypeRepr); + Py_DECREF(paramType); + Py_DECREF(paramRepr); + + return NULL; + } + } + } + + PyObject* returnValue = NULL; + + try + { + // Invoke the wired service + pythonServiceProxy->invokeService(operation); + } + catch(TuscanyRuntimeException& ex) + { + string msg = "Exception whilst invoking the "; + msg += operationName.c_str(); + msg += " operation on an SCA service/reference: "; + msg += ex.getEClassName(); + msg += ": "; + msg += ex.getMessageText(); + logwarning(msg.c_str()); + PyErr_SetString(scaError, msg.c_str()); + return NULL; + } + catch(...) + { + string msg = "Exception whilst invoking the "; + msg += operationName.c_str(); + msg += " operation on an SCA service/reference"; + + logwarning(msg.c_str()); + PyErr_SetString(scaError, msg.c_str()); + return NULL; + } + + + switch(operation.getReturnType()) + { + case Operation::BOOL: + { + if(*(bool*)operation.getReturnValue()) + { + returnValue = Py_True; + } + else + { + returnValue = Py_False; + } + break; + } + case Operation::SHORT: + { + returnValue = PyInt_FromLong(*(short*)operation.getReturnValue()); + break; + } + case Operation::LONG: + { + returnValue = PyLong_FromLong(*(long*)operation.getReturnValue()); + break; + } + case Operation::USHORT: + { + returnValue = PyInt_FromLong(*(unsigned short*)operation.getReturnValue()); + break; + } + case Operation::ULONG: + { + returnValue = PyLong_FromLong(*(unsigned long*)operation.getReturnValue()); + break; + } + case Operation::FLOAT: + { + returnValue = PyFloat_FromDouble(*(float*)operation.getReturnValue()); + break; + } + case Operation::DOUBLE: + { + returnValue = PyFloat_FromDouble(*(double*)operation.getReturnValue()); + break; + } + case Operation::LONGDOUBLE: + { + returnValue = PyFloat_FromDouble(*(long double*)operation.getReturnValue()); + break; + } + case Operation::CHARS: + { + returnValue = PyString_FromString(*(char**)operation.getReturnValue()); + break; + } + case Operation::STRING: + { + returnValue = PyString_FromString((*(string*)operation.getReturnValue()).c_str()); + break; + } + case Operation::DATAOBJECT: + { + if(elementTreeModule != NULL) + { + DataObjectPtr dob = *(DataObjectPtr*)operation.getReturnValue(); + + // Convert a DataObject to a xml.etree.ElementTree Element object + Composite* composite = component->getComposite(); + XMLHelperPtr xmlHelper = composite->getXMLHelper(); + char* str = xmlHelper->save( + dob, + dob->getType().getURI(), + dob->getType().getName()); + + loginfo("Converting SDO DataObject to Python ElementTree: %s", str); + + // Get the xml.etree.ElementTree.XML function + PyObject* elementTreeXMLFunc = PyObject_GetAttrString(elementTreeModule, "XML"); + + // Call the XML() function with the XML string + returnValue = PyObject_CallFunction(elementTreeXMLFunc, "s", str); + + Py_DECREF(elementTreeXMLFunc); + } + else + { + logwarning("Could not convert SDO DataObject to Python ElementTree as ElementTree module could not be loaded. Returning NONE"); + Py_INCREF(Py_None); + returnValue = Py_None; + } + break; + } + default: + { + Py_INCREF(Py_None); + returnValue = Py_None; + } + + } + + Py_XDECREF(elementTreeModuleName); + Py_XDECREF(elementTreeModule); + + return returnValue; +} +static PyMethodDef ModuleMethods[] = +{ + {"locateservice", (PyCFunction) sca_locateservice, METH_VARARGS, "Locates an SCA service & returns an sca_proxy_class instance"}, + {"invoke", (PyCFunction) sca_invoke, METH_VARARGS, "Invoke an operation on an SCA service or reference"}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC initsca(void) +{ + logentry(); + + // Create a new module + PyObject* module = Py_InitModule("sca", ModuleMethods); + + scaError = PyErr_NewException("sca.error", NULL, NULL); + Py_INCREF(scaError); + PyModule_AddObject(module, "error", scaError); +} |