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