diff options
Diffstat (limited to 'sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/PythonServiceWrapper.cpp')
-rw-r--r-- | sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/PythonServiceWrapper.cpp | 1095 |
1 files changed, 1095 insertions, 0 deletions
diff --git a/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/PythonServiceWrapper.cpp b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/PythonServiceWrapper.cpp new file mode 100644 index 0000000000..cb876827bd --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/contrib/runtime/extensions/python/src/tuscany/sca/python/PythonServiceWrapper.cpp @@ -0,0 +1,1095 @@ +/* + * 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 "commonj/sdo/SDO.h" + +#include "tuscany/sca/python/PythonServiceWrapper.h" +#include "tuscany/sca/util/Logging.h" +#include "tuscany/sca/core/Exceptions.h" +#include "tuscany/sca/util/Utils.h" +#include "tuscany/sca/model/Component.h" +#include "tuscany/sca/model/Composite.h" +#include "tuscany/sca/model/ServiceType.h" +#include "tuscany/sca/model/Interface.h" +#include "tuscany/sca/core/SCARuntime.h" +#include "tuscany/sca/python/model/PythonImplementation.h" + +using namespace std; +using namespace commonj::sdo; +using namespace tuscany::sca::model; + +namespace tuscany +{ + namespace sca + { + namespace python + { + + /** + * Prints out PyObject and dir(PyObject) + * for debugging purposes + */ + void printPyObject(char * name, PyObject *pObj) + { + PyObject* pObjRepr = PyObject_Repr(pObj); + loginfo("PyObject %s: %s", name, PyString_AsString(pObjRepr)); + Py_DECREF(pObjRepr); + + PyObject* pObjDir = PyObject_Dir(pObj); + PyObject* pObjDirRepr = PyObject_Repr(pObjDir); + loginfo("PyObject dir(%s): %s", name, PyString_AsString(pObjDirRepr)); + Py_DECREF(pObjDirRepr); + Py_DECREF(pObjDir); + } + + // =========== + // Constructor + // =========== + PythonServiceWrapper::PythonServiceWrapper(Service* service) + : ServiceWrapper(service) + { + logentry(); + + component = service->getComponent(); + implementation = (PythonImplementation*)component->getType(); + + pythonModule = NULL; + pythonClassInstance = NULL; + + // ----------------------------------------------- + // Get the implementation for the target component + // ----------------------------------------------- + PythonImplementation* impl = (PythonImplementation*)component->getType(); + if (!impl) + { + string msg = "Component " + component->getName() + " has no implementation defined"; + throwException(SystemConfigurationException, msg.c_str()); + } + + // Initialize the Python environment + Py_Initialize(); + + // Add the path to the composite (+ any further path specified) to the Python sys.path + string path = component->getComposite()->getRoot(); + if(impl->getModulePath().size() > 0) + { + path += "/" + impl->getModulePath(); + } + + loginfo("Module: %s", impl->getModule().c_str()); + loginfo("Path: %s", path.c_str()); + loginfo("Class: %s", impl->getClass().c_str()); + + PyObject* pSysName = PyString_FromString("sys"); + PyObject* pSys = PyImport_Import(pSysName); + Py_DECREF(pSysName); + + if(pSys != NULL) + { + PyObject* pSysPath = PyObject_GetAttrString(pSys, "path"); + + if(pSysPath != NULL && PyList_Check(pSysPath)) + { + PyObject* pPath = PyString_FromString(path.c_str()); + PyList_Append(pSysPath, pPath); + + Py_DECREF(pPath); + Py_DECREF(pSysPath); + } + Py_DECREF(pSys); + } + + if(&(impl->getModule()) != NULL && impl->getModule().size() > 0) + { + // Now import the module + PyObject* pModuleName = PyString_FromString(impl->getModule().c_str()); + + pythonModule = PyImport_Import(pModuleName); + Py_DECREF(pModuleName); + } + + if (!pythonModule) + { + if(PyErr_Occurred()) + { + PyErr_Print(); + } + string msg = "Failed to load module named " + impl->getModule() + " on path " + path; + throwException(SystemConfigurationException, msg.c_str()); + } + printPyObject("pythonModule",pythonModule); + } + + // ========== + // Destructor + // ========== + PythonServiceWrapper::~PythonServiceWrapper() + { + logentry(); + + Py_XDECREF(pythonClassInstance); + Py_XDECREF(pythonModule); + Py_Finalize(); + } + + // ====================================================================== + // newInstance: create a new class instance + // ====================================================================== + PyObject* PythonServiceWrapper::newInstance() + { + logentry(); + + PythonImplementation* impl = (PythonImplementation*)component->getType(); + string className = impl->getClass(); + + PyObject* pClassInstance = NULL; + if (pythonModule != NULL) + { + if(&className != NULL && className.size() > 0) + { + // We have a class name, so create an instance and use this to invoke the correct function + PyObject* pClass = PyObject_GetAttrString(pythonModule, (char*) className.c_str()); + + if(pClass == NULL) + { + if(PyErr_Occurred()) + { + PyErr_Print(); + } + string msg = "Cannot find class named " + className + " in Python module"; + throwException(SystemConfigurationException, msg.c_str()); + } + + pClassInstance = PyInstance_New(pClass, NULL, NULL); + + if(pClassInstance == NULL || !PyInstance_Check(pClassInstance)) + { + if(PyErr_Occurred()) + { + PyErr_Print(); + } + string msg = "Could not create new instance of class named " + className + " in Python module"; + throwException(ServiceInvocationException, msg.c_str()); + } + Py_XDECREF(pClass); + } + } + return pClassInstance; + } + + // ====================================================================== + // getInstance: get a class instance for this scope + // ====================================================================== + PyObject* PythonServiceWrapper::getInstance() + { + logentry(); + + PythonImplementation::Scope scope = implementation->getScope(); + if (scope == PythonImplementation::COMPOSITE) + { + if (!pythonClassInstance) + { + pythonClassInstance = newInstance(); + } + return pythonClassInstance; + } + else // (scope == PythonImplementation::STATELESS) + { + return newInstance(); + } + } + + // ====================================================================== + // releaseImplementation: release the implementation for this scope + // ====================================================================== + void PythonServiceWrapper::releaseInstance() + { + logentry(); + + PythonImplementation::Scope scope = implementation->getScope(); + if(scope == PythonImplementation::STATELESS) + { + // Delete the class instance if there is one + if(pythonClassInstance != NULL && PyInstance_Check(pythonClassInstance)) + { + Py_DECREF(pythonClassInstance); + pythonClassInstance = NULL; + } + + // Need to reload the module + PyObject* reloadedPythonModule = PyImport_ReloadModule(pythonModule); + + if(reloadedPythonModule != NULL) + { + // Get rid of old pythonModule and replace with the reloaded one + Py_DECREF(pythonModule); + pythonModule = reloadedPythonModule; + } + } + } + + // ====================================================================== + // invoke: wrapper call to service with setting the component context + // ====================================================================== + void PythonServiceWrapper::invoke(Operation& operation) + { + logentry(); + + SCARuntime* runtime = SCARuntime::getCurrentRuntime(); + runtime->setCurrentComponent(component); + + + // Load the references & properties into the module + addReferences(pythonModule); + addProperties(pythonModule); + + try + { + loginfo("Operation: %s", operation.getName().c_str()); + + PyObject* pFunc = NULL; + pythonClassInstance = getInstance(); + + if(pythonClassInstance != NULL && PyInstance_Check(pythonClassInstance)) + { + // Get the function from the instance + pFunc = PyObject_GetAttrString(pythonClassInstance, (char*) operation.getName().c_str()); + } + if(pFunc == NULL && pythonModule != NULL) + { + // Get the function directly from the module if it could not be got from an instance + pFunc = PyObject_GetAttrString(pythonModule, (char*) operation.getName().c_str()); + } + if(pFunc == NULL) + { + // Can't get the function from the class or module + string msg = "Python module or class instance has not been created"; + throwException(ServiceInvocationException, msg.c_str()); + } + + if (pFunc && PyCallable_Check(pFunc)) + { + PyObject* pArgs = PyTuple_New(operation.getNParms()); + PyObject* pKeywordsDict = PyDict_New(); + PyObject* pValue = NULL; + + // 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"); + } + + for(unsigned int i = 0; i < operation.getNParms(); i++) + { + const Operation::Parameter& parm = operation.getParameter(i); + switch(parm.getType()) + { + case Operation::BOOL: + { + if( *(bool*)parm.getValue()) + { + //boolean true + pValue = Py_True; + } + else + { + pValue = Py_False; + } + break; + } + case Operation::SHORT: + { + pValue = PyInt_FromLong(*(short*)parm.getValue()); + break; + } + case Operation::USHORT: + { + pValue = PyInt_FromLong(*(unsigned short*)parm.getValue()); + break; + } + case Operation::INT: + { + pValue = PyInt_FromLong(*(int*)parm.getValue()); + break; + } + case Operation::UINT: + { + pValue = PyInt_FromLong(*(unsigned int*)parm.getValue()); + break; + } + case Operation::LONG: + { + pValue = PyLong_FromLong(*(long*)parm.getValue()); + break; + } + case Operation::ULONG: + { + pValue = PyLong_FromUnsignedLong(*(unsigned long*)parm.getValue()); + break; + } + case Operation::FLOAT: + { + pValue = PyFloat_FromDouble(*(float*)parm.getValue()); + break; + } + case Operation::DOUBLE: + { + pValue = PyFloat_FromDouble(*(double*)parm.getValue()); + break; + } + case Operation::LONGDOUBLE: + { + pValue = PyFloat_FromDouble(*(long double*)parm.getValue()); + break; + } + case Operation::CHARS: + { + pValue = PyString_FromString(*(char**)parm.getValue()); + break; + } + case Operation::STRING: + { + pValue = PyString_FromString((*(string*)parm.getValue()).c_str()); + break; + } + case Operation::DATAOBJECT: + { + if(elementTreeModule != NULL) + { + DataObjectPtr dob = *(DataObjectPtr*)parm.getValue(); + + // 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 + pValue = PyObject_CallFunction(elementTreeXMLFunc, "s", str); + + Py_DECREF(elementTreeXMLFunc); + } + else + { + throwException(ServiceDataException, "Could not convert SDO DataObject to Python ElementTree as ElementTree module could not be loaded"); + } + break; + } + default: + throwException(ServiceDataException, "Operation parameter type not supported"); + } + + if (!pValue) + { + Py_DECREF(pArgs); + + if(PyErr_Occurred()) + { + PyErr_Print(); + } + + string msg = "Error converting parameter into Python type"; + throwException(ServiceDataException, msg.c_str()); + + } + //printPyObject("Param value", pValue); + + // If we have a param name, put it in the keyword args + if(parm.hasName()) + { + PyDict_SetItemString(pKeywordsDict, parm.getName().c_str(), pValue); + Py_DECREF(pValue); + } + else + { + /* pValue reference stolen here: */ + PyTuple_SetItem(pArgs, i, pValue); + } + } + + // Resize the args to the correct length + _PyTuple_Resize(&pArgs, operation.getNParms() - PyDict_Size(pKeywordsDict)); + + loginfo("Calling python func with %d args and %d keyword args", PyTuple_Size(pArgs), PyDict_Size(pKeywordsDict)); + + pValue = PyObject_Call(pFunc, pArgs, pKeywordsDict); + //printPyObject("Return value", pValue); + + Py_DECREF(pArgs); + if (pValue != NULL) + { + char buf[20]; + if(PyInt_Check(pValue) || PyLong_Check(pValue)) + { + long* data = new long; + if(PyInt_Check(pValue)) + { + loginfo("Int return value: %d", PyInt_AsLong(pValue)); + *data = PyInt_AsLong(pValue); + } + else + { + loginfo("Long return value: %l", PyLong_AsLong(pValue)); + *data = PyLong_AsLong(pValue); + } + + // Check if the return type has already been set (for typed languages) + switch(operation.getReturnType()) + { + case Operation::BOOL: + { + *(bool*)operation.getReturnValue() = (*data != 0); + break; + } + case Operation::SHORT: + { + *(short*)operation.getReturnValue() = (short)*data; + break; + } + case Operation::USHORT: + { + *(unsigned short*)operation.getReturnValue() = (unsigned short)*data; + break; + } + case Operation::INT: + { + *(int*)operation.getReturnValue() = (int)*data; + break; + } + case Operation::UINT: + { + *(unsigned int*)operation.getReturnValue() = (unsigned int)*data; + break; + } + case Operation::LONG: + { + *(long*)operation.getReturnValue() = (long)*data; + break; + } + case Operation::ULONG: + { + *(unsigned long*)operation.getReturnValue() = (unsigned long)*data; + break; + } + case Operation::FLOAT: + { + *(float*)operation.getReturnValue() = (float)*data; + break; + } + case Operation::DOUBLE: + { + *(double*)operation.getReturnValue() = (double)*data; + break; + } + case Operation::LONGDOUBLE: + { + *(long double*)operation.getReturnValue() = (long double)*data; + break; + } + case Operation::CHARS: + { + sprintf(buf, "%d", *data); + *(char**)operation.getReturnValue() = buf; + break; + } + case Operation::STRING: + { + sprintf(buf, "%d", *data); + *(string*)operation.getReturnValue() = buf; + break; + } + default: + { + // The type is set as something else or has not been set + operation.setReturnValue(data); + } + } + } + else if(PyBool_Check(pValue)) + { + loginfo("Bool return value: %d", (pValue == Py_True)); + bool* data = new bool; + *data = (pValue == Py_True); + + // Check if the return type has already been set (for typed languages) + switch(operation.getReturnType()) + { + case Operation::BOOL: + { + *(bool*)operation.getReturnValue() = *data; + break; + } + case Operation::SHORT: + { + *(short*)operation.getReturnValue() = (short)*data; + break; + } + case Operation::USHORT: + { + *(unsigned short*)operation.getReturnValue() = (unsigned short)*data; + break; + } + case Operation::INT: + { + *(int*)operation.getReturnValue() = (int)*data; + break; + } + case Operation::UINT: + { + *(unsigned int*)operation.getReturnValue() = (unsigned int)*data; + break; + } + case Operation::LONG: + { + *(long*)operation.getReturnValue() = (long)*data; + break; + } + case Operation::ULONG: + { + *(unsigned long*)operation.getReturnValue() = (unsigned long)*data; + break; + } + case Operation::FLOAT: + { + *(float*)operation.getReturnValue() = (float)*data; + break; + } + case Operation::DOUBLE: + { + *(double*)operation.getReturnValue() = (double)*data; + break; + } + case Operation::LONGDOUBLE: + { + *(long double*)operation.getReturnValue() = (long double)*data; + break; + } + case Operation::CHARS: + { + if(*data) + { + *(char**)operation.getReturnValue() = "true"; + } + else + { + *(char**)operation.getReturnValue() = "false"; + } + break; + } + case Operation::STRING: + { + if(*data) + { + *(string*)operation.getReturnValue() = "true"; + } + else + { + *(string*)operation.getReturnValue() = "false"; + } + break; + } + default: + { + // The type is set as something else or has not been set + operation.setReturnValue(data); + } + } + } + else if(PyFloat_Check(pValue)) + { + loginfo("Float return value: %f", PyFloat_AsDouble(pValue)); + + double* data = new double; + *data = PyFloat_AsDouble(pValue); + + // Check if the return type has already been set (for typed languages) + switch(operation.getReturnType()) + { + case Operation::BOOL: + { + *(bool*)operation.getReturnValue() = (*data != 0.0); + break; + } + case Operation::SHORT: + { + *(short*)operation.getReturnValue() = (short)*data; + break; + } + case Operation::USHORT: + { + *(unsigned short*)operation.getReturnValue() = (unsigned short)*data; + break; + } + case Operation::INT: + { + *(int*)operation.getReturnValue() = (int)*data; + break; + } + case Operation::UINT: + { + *(unsigned int*)operation.getReturnValue() = (unsigned int)*data; + break; + } + case Operation::LONG: + { + *(long*)operation.getReturnValue() = (long)*data; + break; + } + case Operation::ULONG: + { + *(unsigned long*)operation.getReturnValue() = (unsigned long)*data; + break; + } + case Operation::FLOAT: + { + *(float*)operation.getReturnValue() = (float)*data; + break; + } + case Operation::DOUBLE: + { + *(double*)operation.getReturnValue() = (double)*data; + break; + } + case Operation::LONGDOUBLE: + { + *(long double*)operation.getReturnValue() = (long double)*data; + break; + } + case Operation::CHARS: + { + sprintf(buf, "%f", *data); + *(char**)operation.getReturnValue() = buf; + break; + } + case Operation::STRING: + { + sprintf(buf, "%f", *data); + *(string*)operation.getReturnValue() = buf; + break; + } + default: + { + // The type is set as something else or has not been set + operation.setReturnValue(data); + } + } + } + else if(PyString_Check(pValue)) + { + loginfo("String return value: %s", PyString_AsString(pValue)); + const char** data = new const char*; + *data = PyString_AsString(pValue); + + // Check if the return type has already been set (for typed languages) + switch(operation.getReturnType()) + { + case Operation::BOOL: + { + // If the string is empty or "0" or "false" set to false, otherwise true + if(strlen(*data) == 0 || strcmp(*data, "0") == 0 || strcmp(*data, "false") == 0) + { + *(bool*)operation.getReturnValue() = false; + } + else + { + *(bool*)operation.getReturnValue() = true; + } + break; + } + case Operation::SHORT: + { + *(short*)operation.getReturnValue() = (short)atoi(*data); + break; + } + case Operation::USHORT: + { + *(unsigned short*)operation.getReturnValue() = (unsigned short)atoi(*data); + break; + } + case Operation::INT: + { + *(int*)operation.getReturnValue() = (int)atoi(*data); + break; + } + case Operation::UINT: + { + *(unsigned int*)operation.getReturnValue() = (unsigned int)atoi(*data); + break; + } + case Operation::LONG: + { + *(long*)operation.getReturnValue() = (long)atol(*data); + break; + } + case Operation::ULONG: + { + *(unsigned long*)operation.getReturnValue() = (unsigned long)atol(*data); + break; + } + case Operation::FLOAT: + { + *(float*)operation.getReturnValue() = (float)atof(*data); + break; + } + case Operation::DOUBLE: + { + *(double*)operation.getReturnValue() = (double)atof(*data); + break; + } + case Operation::LONGDOUBLE: + { + *(long double*)operation.getReturnValue() = (long double)atof(*data); + break; + } + case Operation::CHARS: + { + *(const char**)operation.getReturnValue() = *data; + break; + } + case Operation::STRING: + { + *(string*)operation.getReturnValue() = *data; + break; + } + default: + { + // The type is set as something else or has not been set + string* stringData = new string; + *stringData = *data; + operation.setReturnValue(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", pValue); + Py_DECREF(elementTreeIsElementFunc); + } + + 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", pValue); + char* data = PyString_AsString(pElemString); + + 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.setReturnValue(dataObjectData); + } + else + { + string msg = "xml.etree.ElementTree.Element could not be converted to a DataObject"; + throwException(ServiceDataException, msg.c_str()); + } + + Py_DECREF(elementTreeToStringFunc); + Py_DECREF(pElemString); + } + else + { + PyObject* valueRepr = PyObject_Repr(pValue); + PyObject* valueType = PyObject_Type(pValue); + PyObject* valueTypeRepr = PyObject_Repr(valueType); + loginfo("Return value of unknown type (%s) has repr: %s", PyString_AsString(valueTypeRepr), PyString_AsString(valueRepr)); + Py_DECREF(valueTypeRepr); + Py_DECREF(valueType); + Py_DECREF(valueRepr); + } + + Py_DECREF(pIsElement); + } + + Py_DECREF(elementTreeModule); + Py_DECREF(elementTreeModuleName); + Py_DECREF(pValue); + } + else + { + Py_DECREF(pFunc); + Py_XDECREF(elementTreeModule); + Py_XDECREF(elementTreeModuleName); + + string msg = "Error whilst calling Python function "+operation.getName()+": "; + if(PyErr_Occurred()) + { + PyObject *pErrorType, *pErrorValue, *pErrorTraceback; + PyErr_Fetch(&pErrorType, &pErrorValue, &pErrorTraceback); + + if (pErrorType != NULL && pErrorValue != NULL) + { + PyObject* pErrorTypeStr = PyObject_Str(pErrorType); + PyObject* pErrorValueStr = PyObject_Str(pErrorValue); + msg += PyString_AsString(pErrorTypeStr); + msg += " : "; + msg += PyString_AsString(pErrorValueStr); + Py_DECREF(pErrorTypeStr); + Py_DECREF(pErrorValueStr); + } + else + { + msg += "No Python Error information provided"; + } + Py_XDECREF(pErrorType); + Py_XDECREF(pErrorValue); + Py_XDECREF(pErrorTraceback); + + PyErr_Print(); + } + + throwException(ServiceInvocationException, msg.c_str()); + } + } + else + { + if (PyErr_Occurred()) + { + PyErr_Print(); + } + string msg = "Cannot find the operation named " + operation.getName() + " in the Python module"; + throwException(ServiceInvocationException, msg.c_str()); + } + Py_XDECREF(pFunc); + + } + catch (...) + { + releaseInstance(); + runtime->unsetCurrentComponent(); + throw; + } + releaseInstance(); + runtime->unsetCurrentComponent(); + } + + + // ========================================================================== + // Add any properties into the loaded implementation module as Python objects + // ========================================================================== + void PythonServiceWrapper::addProperties(PyObject* module) + { + logentry(); + + // Set all the configured properties + DataObjectPtr properties = component->getProperties(); + PropertyList pl = properties->getInstanceProperties(); + + for (unsigned int i = 0; i < pl.size(); i++) + { + if (properties->isSet(pl[i])) + { + string propName = pl[i].getName(); + string propValue = properties->getCString(pl[i]); + PyObject* property; + + if(pl[i].isMany()) + { + //TODO - deal with properties that are many + } + + switch(pl[i].getTypeEnum()) + { + case Type::BooleanType: + { + if(properties->getBoolean(pl[i])) + { + property = Py_True; + } + else + { + property = Py_False; + } + Py_INCREF(property); + break; + } + case Type::BigIntegerType: + case Type::BigDecimalType: + case Type::LongType: + { + property = PyLong_FromLongLong(properties->getLong(pl[i])); + break; + } + case Type::ShortType: + case Type::IntType: + { + property = PyInt_FromLong(properties->getInt(pl[i])); + break; + } + case Type::DoubleType: + case Type::FloatType: + { + property = PyFloat_FromDouble(properties->getDouble(pl[i])); + break; + } + case Type::DataObjectType: + { + // Serialize a DataObject and create a python string object from the XML + DataObjectPtr data = properties->getDataObject(pl[i]); + XMLHelperPtr helper = HelperProvider::getXMLHelper(properties->getDataFactory()); + string serializedData = helper->save(data, + data->getType().getURI(), + data->getType().getName()); + + loginfo("Converting SDO DataObject to Python ElementTree: %s", serializedData.c_str()); + + // Get the xml.etree.ElementTree.XML function + PyObject* elementTreeModuleName = PyString_FromString("xml.etree.ElementTree"); + PyObject* elementTreeModule = PyImport_Import(elementTreeModuleName); + PyObject* elementTreeXMLFunc = PyObject_GetAttrString(elementTreeModule, "XML"); + + // Call the XML() function with the XML string + property = PyObject_CallFunction(elementTreeXMLFunc, "s", serializedData.c_str()); + + Py_DECREF(elementTreeXMLFunc); + Py_DECREF(elementTreeModule); + Py_DECREF(elementTreeModuleName); + break; + } + case Type::CharacterType: + case Type::StringType: + case Type::TextType: + case Type::UriType: + default: + { + // For strings and by default create a python string object + property = PyString_FromString(propValue.c_str()); + break; + } + } + + int success = PyModule_AddObject(module, (char*)propName.c_str(), property); + + if(success == 0) + { + loginfo("Added property named %s with type %s and value %s to python module", propName.c_str(), pl[i].getType().getName(), propValue.c_str()); + } + else + { + logwarning("Failed to add property named %s to python module", propName.c_str()); + } + } + } + } + + + // ====================================================================== + // Add any references into the loaded implementation module as class instances that look like + // the classes defined in the interface.python xml + // ====================================================================== + void PythonServiceWrapper::addReferences(PyObject* module) + { + logentry(); + + // Import the TuscanySCA 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"; + logwarning(msg.c_str()); + } + else + { + // Get the sca_proxy class + PyObject* sca_proxy_class = PyObject_GetAttrString(sca_proxy_module, "sca_proxy_class"); + + // Iterate through the references of the current component, adding + // each reference to the module + Component::REFERENCE_MAP references = component->getReferences(); + Component::REFERENCE_MAP::iterator pos; + for( pos = references.begin(); pos != references.end(); ++pos) + { + ReferenceType* referenceType = ((Reference*) pos->second)->getType(); + string referenceName = referenceType->getName(); + + PyObject* tuscanySCAArgs = PyTuple_New(2); + PyObject* refName = PyString_FromString(referenceType->getName().c_str()); + PyTuple_SetItem(tuscanySCAArgs, 0, refName); + Py_INCREF(Py_True); + PyTuple_SetItem(tuscanySCAArgs, 1, Py_True); + + // Create the instance of the TuscanySCAReference class + PyObject* sca_proxy_classInstance = PyInstance_New(sca_proxy_class, tuscanySCAArgs, NULL); + Py_DECREF(tuscanySCAArgs); + + int success = PyModule_AddObject(module, (char*)referenceName.c_str(), sca_proxy_classInstance); + + if(success == 0) + { + loginfo("Successfully added sca_proxy_class instance as %s to pythonModule", referenceName.c_str()); + } + else + { + logwarning("Failed to add sca_proxy_class instance as %s to pythonModule", referenceName.c_str()); + } + } + Py_DECREF(sca_proxy_module); + } + } + } // End namespace python + } // End namespace sca +} // End namespace tuscany |