1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include <pyuno/pyuno.hxx> 25 26 #include <osl/process.h> 27 #include <osl/file.h> 28 #include <osl/thread.h> 29 30 #include <rtl/ustrbuf.hxx> 31 #include <rtl/strbuf.hxx> 32 #include <rtl/bootstrap.hxx> 33 34 #include <cppuhelper/implementationentry.hxx> 35 #include <cppuhelper/factory.hxx> 36 37 using rtl::OUString; 38 using rtl::OUStringBuffer; 39 using rtl::OString; 40 41 using pyuno::PyRef; 42 using pyuno::Runtime; 43 using pyuno::PyThreadAttach; 44 45 using com::sun::star::registry::XRegistryKey; 46 using com::sun::star::uno::Reference; 47 using com::sun::star::uno::XInterface; 48 using com::sun::star::uno::Sequence; 49 using com::sun::star::uno::XComponentContext; 50 using com::sun::star::uno::RuntimeException; 51 52 namespace pyuno_loader 53 { 54 55 static void raiseRuntimeExceptionWhenNeeded() throw ( RuntimeException ) 56 { 57 if( PyErr_Occurred() ) 58 { 59 PyRef excType, excValue, excTraceback; 60 PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback); 61 Runtime runtime; 62 com::sun::star::uno::Any a = runtime.extractUnoException( excType, excValue, excTraceback ); 63 OUStringBuffer buf; 64 buf.appendAscii( "python-loader:" ); 65 if( a.hasValue() ) 66 buf.append( ((com::sun::star::uno::Exception *)a.getValue())->Message ); 67 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () ); 68 } 69 } 70 71 static PyRef getLoaderModule() throw( RuntimeException ) 72 { 73 PyRef module( 74 PyImport_ImportModule( const_cast< char * >("pythonloader") ), 75 SAL_NO_ACQUIRE ); 76 raiseRuntimeExceptionWhenNeeded(); 77 if( !module.is() ) 78 { 79 throw RuntimeException( 80 OUString( RTL_CONSTASCII_USTRINGPARAM( "pythonloader: Couldn't load pythonloader module" ) ), 81 Reference< XInterface > () ); 82 } 83 return PyRef( PyModule_GetDict( module.get() )); 84 } 85 86 static PyRef getObjectFromLoaderModule( const char * func ) 87 throw ( RuntimeException ) 88 { 89 PyRef object( PyDict_GetItemString(getLoaderModule().get(), (char*)func ) ); 90 if( !object.is() ) 91 { 92 OUStringBuffer buf; 93 buf.appendAscii( "pythonloader: couldn't find core element pythonloader." ); 94 buf.appendAscii( func ); 95 throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >()); 96 } 97 return object; 98 } 99 100 OUString getImplementationName() 101 { 102 return OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.pyuno.Loader" ) ); 103 } 104 105 Sequence< OUString > getSupportedServiceNames() 106 { 107 OUString serviceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.loader.Python" ) ); 108 return Sequence< OUString > ( &serviceName, 1 ); 109 } 110 111 static void setPythonHome ( const OUString & pythonHome ) 112 { 113 OUString systemPythonHome; 114 osl_getSystemPathFromFileURL( pythonHome.pData, &(systemPythonHome.pData) ); 115 OString o = rtl::OUStringToOString( systemPythonHome, osl_getThreadTextEncoding() ); 116 static wchar_t *wpath = Py_DecodeLocale(o.pData->buffer, NULL); 117 if (wpath == NULL) { 118 PyErr_SetString(PyExc_SystemError, "Cannot decode python home path"); 119 return; 120 } 121 Py_SetPythonHome(wpath); 122 } 123 124 static void prependPythonPath( const OUString & pythonPathBootstrap ) 125 { 126 rtl::OUStringBuffer bufPYTHONPATH( 256 ); 127 sal_Int32 nIndex = 0; 128 while( 1 ) 129 { 130 sal_Int32 nNew = pythonPathBootstrap.indexOf( ' ', nIndex ); 131 OUString fileUrl; 132 if( nNew == -1 ) 133 { 134 fileUrl = OUString( &( pythonPathBootstrap[nIndex] ) ); 135 } 136 else 137 { 138 fileUrl = OUString( &(pythonPathBootstrap[nIndex]) , nNew - nIndex ); 139 } 140 OUString systemPath; 141 osl_getSystemPathFromFileURL( fileUrl.pData, &(systemPath.pData) ); 142 bufPYTHONPATH.append( systemPath ); 143 bufPYTHONPATH.append( static_cast<sal_Unicode>(SAL_PATHSEPARATOR) ); 144 if( nNew == -1 ) 145 break; 146 nIndex = nNew + 1; 147 } 148 const char * oldEnv = getenv( "PYTHONPATH"); 149 if( oldEnv ) 150 bufPYTHONPATH.append( rtl::OUString(oldEnv, strlen(oldEnv), osl_getThreadTextEncoding()) ); 151 152 rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("PYTHONPATH")); 153 rtl::OUString envValue(bufPYTHONPATH.makeStringAndClear()); 154 osl_setEnvironment(envVar.pData, envValue.pData); 155 } 156 157 Reference< XInterface > CreateInstance( const Reference< XComponentContext > & ctx ) 158 { 159 Reference< XInterface > ret; 160 161 if( ! Py_IsInitialized() ) 162 { 163 OUString pythonPath; 164 OUString pythonHome; 165 OUString path( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR/program/" SAL_CONFIGFILE("pythonloader.uno" ))); 166 rtl::Bootstrap::expandMacros(path); //TODO: detect failure 167 rtl::Bootstrap bootstrap(path); 168 169 // look for pythonhome 170 bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONHOME") ), pythonHome ); 171 bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONPATH" ) ) , pythonPath ); 172 173 // pythonhome+pythonpath must be set before Py_Initialize(), otherwise there appear warning on the console 174 // sadly, there is no api for setting the pythonpath, we have to use the environment variable 175 if( pythonHome.getLength() ) 176 setPythonHome( pythonHome ); 177 178 if( pythonPath.getLength() ) 179 prependPythonPath( pythonPath ); 180 181 // initialize python 182 Py_Initialize(); 183 184 PyThreadState *tstate = PyThreadState_Get(); 185 PyEval_ReleaseThread( tstate ); 186 } 187 188 PyThreadAttach attach( PyInterpreterState_Head() ); 189 { 190 if( ! Runtime::isInitialized() ) 191 { 192 Runtime::initialize( ctx ); 193 } 194 Runtime runtime; 195 196 PyRef pyCtx = runtime.any2PyObject( 197 com::sun::star::uno::makeAny( ctx ) ); 198 199 PyRef clazz = getObjectFromLoaderModule( "Loader" ); 200 PyRef args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE ); 201 PyTuple_SetItem( args.get(), 0 , pyCtx.getAcquired() ); 202 PyRef pyInstance( PyObject_CallObject( clazz.get() , args.get() ), SAL_NO_ACQUIRE ); 203 runtime.pyObject2Any( pyInstance ) >>= ret; 204 } 205 return ret; 206 } 207 208 } 209 210 211 static struct cppu::ImplementationEntry g_entries[] = 212 { 213 { 214 pyuno_loader::CreateInstance, pyuno_loader::getImplementationName, 215 pyuno_loader::getSupportedServiceNames, cppu::createSingleComponentFactory, 216 0 , 0 217 }, 218 { 0, 0, 0, 0, 0, 0 } 219 }; 220 221 extern "C" 222 { 223 224 //================================================================================================== 225 SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( 226 const sal_Char ** ppEnvTypeName, uno_Environment ** ) 227 { 228 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 229 } 230 //================================================================================================== 231 SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( 232 const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) 233 { 234 return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries ); 235 } 236 237 } 238