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() 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() 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 { 88 PyRef object( PyDict_GetItemString(getLoaderModule().get(), (char*)func ) ); 89 if( !object.is() ) 90 { 91 OUStringBuffer buf; 92 buf.appendAscii( "pythonloader: couldn't find core element pythonloader." ); 93 buf.appendAscii( func ); 94 throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >()); 95 } 96 return object; 97 } 98 99 OUString getImplementationName() 100 { 101 return OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.pyuno.Loader" ) ); 102 } 103 104 Sequence< OUString > getSupportedServiceNames() 105 { 106 OUString serviceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.loader.Python" ) ); 107 return Sequence< OUString > ( &serviceName, 1 ); 108 } 109 110 static void setPythonHome ( const OUString & pythonHome ) 111 { 112 OUString systemPythonHome; 113 osl_getSystemPathFromFileURL( pythonHome.pData, &(systemPythonHome.pData) ); 114 OString o = rtl::OUStringToOString( systemPythonHome, osl_getThreadTextEncoding() ); 115 static wchar_t *wpath = Py_DecodeLocale(o.pData->buffer, NULL); 116 if (wpath == NULL) { 117 PyErr_SetString(PyExc_SystemError, "Cannot decode python home path"); 118 return; 119 } 120 Py_SetPythonHome(wpath); 121 } 122 123 static void prependPythonPath( const OUString & pythonPathBootstrap ) 124 { 125 rtl::OUStringBuffer bufPYTHONPATH( 256 ); 126 sal_Int32 nIndex = 0; 127 while( 1 ) 128 { 129 sal_Int32 nNew = pythonPathBootstrap.indexOf( ' ', nIndex ); 130 OUString fileUrl; 131 if( nNew == -1 ) 132 { 133 fileUrl = OUString( &( pythonPathBootstrap[nIndex] ) ); 134 } 135 else 136 { 137 fileUrl = OUString( &(pythonPathBootstrap[nIndex]) , nNew - nIndex ); 138 } 139 OUString systemPath; 140 osl_getSystemPathFromFileURL( fileUrl.pData, &(systemPath.pData) ); 141 bufPYTHONPATH.append( systemPath ); 142 bufPYTHONPATH.append( static_cast<sal_Unicode>(SAL_PATHSEPARATOR) ); 143 if( nNew == -1 ) 144 break; 145 nIndex = nNew + 1; 146 } 147 const char * oldEnv = getenv( "PYTHONPATH"); 148 if( oldEnv ) 149 bufPYTHONPATH.append( rtl::OUString(oldEnv, strlen(oldEnv), osl_getThreadTextEncoding()) ); 150 151 rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("PYTHONPATH")); 152 rtl::OUString envValue(bufPYTHONPATH.makeStringAndClear()); 153 osl_setEnvironment(envVar.pData, envValue.pData); 154 } 155 156 Reference< XInterface > CreateInstance( const Reference< XComponentContext > & ctx ) 157 { 158 Reference< XInterface > ret; 159 160 if( ! Py_IsInitialized() ) 161 { 162 OUString pythonPath; 163 OUString pythonHome; 164 OUString path( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR/program/" SAL_CONFIGFILE("pythonloader.uno" ))); 165 rtl::Bootstrap::expandMacros(path); //TODO: detect failure 166 rtl::Bootstrap bootstrap(path); 167 168 // look for pythonhome 169 bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONHOME") ), pythonHome ); 170 bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONPATH" ) ) , pythonPath ); 171 172 // pythonhome+pythonpath must be set before Py_Initialize(), otherwise there appear warning on the console 173 // sadly, there is no api for setting the pythonpath, we have to use the environment variable 174 if( pythonHome.getLength() ) 175 setPythonHome( pythonHome ); 176 177 if( pythonPath.getLength() ) 178 prependPythonPath( pythonPath ); 179 180 // initialize python 181 Py_Initialize(); 182 183 PyThreadState *tstate = PyThreadState_Get(); 184 PyEval_ReleaseThread( tstate ); 185 } 186 187 PyThreadAttach attach( PyInterpreterState_Head() ); 188 { 189 if( ! Runtime::isInitialized() ) 190 { 191 Runtime::initialize( ctx ); 192 } 193 Runtime runtime; 194 195 PyRef pyCtx = runtime.any2PyObject( 196 com::sun::star::uno::makeAny( ctx ) ); 197 198 PyRef clazz = getObjectFromLoaderModule( "Loader" ); 199 PyRef args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE ); 200 PyTuple_SetItem( args.get(), 0 , pyCtx.getAcquired() ); 201 PyRef pyInstance( PyObject_CallObject( clazz.get() , args.get() ), SAL_NO_ACQUIRE ); 202 runtime.pyObject2Any( pyInstance ) >>= ret; 203 } 204 return ret; 205 } 206 207 } 208 209 210 static struct cppu::ImplementationEntry g_entries[] = 211 { 212 { 213 pyuno_loader::CreateInstance, pyuno_loader::getImplementationName, 214 pyuno_loader::getSupportedServiceNames, cppu::createSingleComponentFactory, 215 0 , 0 216 }, 217 { 0, 0, 0, 0, 0, 0 } 218 }; 219 220 extern "C" 221 { 222 223 //================================================================================================== 224 SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( 225 const sal_Char ** ppEnvTypeName, uno_Environment ** ) 226 { 227 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 228 } 229 //================================================================================================== 230 SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( 231 const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) 232 { 233 return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries ); 234 } 235 236 } 237