1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include <pyuno/pyuno.hxx> 29 30 #include <osl/process.h> 31 #include <osl/file.h> 32 #include <osl/thread.h> 33 34 #include <rtl/ustrbuf.hxx> 35 #include <rtl/strbuf.hxx> 36 #include <rtl/bootstrap.hxx> 37 38 #include <cppuhelper/implementationentry.hxx> 39 #include <cppuhelper/factory.hxx> 40 41 using rtl::OUString; 42 using rtl::OUStringBuffer; 43 using rtl::OString; 44 45 using pyuno::PyRef; 46 using pyuno::Runtime; 47 using pyuno::PyThreadAttach; 48 49 using com::sun::star::registry::XRegistryKey; 50 using com::sun::star::uno::Reference; 51 using com::sun::star::uno::XInterface; 52 using com::sun::star::uno::Sequence; 53 using com::sun::star::uno::XComponentContext; 54 using com::sun::star::uno::RuntimeException; 55 56 namespace pyuno_loader 57 { 58 59 static void raiseRuntimeExceptionWhenNeeded() throw ( RuntimeException ) 60 { 61 if( PyErr_Occurred() ) 62 { 63 PyRef excType, excValue, excTraceback; 64 PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback); 65 Runtime runtime; 66 com::sun::star::uno::Any a = runtime.extractUnoException( excType, excValue, excTraceback ); 67 OUStringBuffer buf; 68 buf.appendAscii( "python-loader:" ); 69 if( a.hasValue() ) 70 buf.append( ((com::sun::star::uno::Exception *)a.getValue())->Message ); 71 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () ); 72 } 73 } 74 75 static PyRef getLoaderModule() throw( RuntimeException ) 76 { 77 PyRef module( 78 PyImport_ImportModule( const_cast< char * >("pythonloader") ), 79 SAL_NO_ACQUIRE ); 80 raiseRuntimeExceptionWhenNeeded(); 81 if( !module.is() ) 82 { 83 throw RuntimeException( 84 OUString( RTL_CONSTASCII_USTRINGPARAM( "pythonloader: Couldn't load pythonloader module" ) ), 85 Reference< XInterface > () ); 86 } 87 return PyRef( PyModule_GetDict( module.get() )); 88 } 89 90 static PyRef getObjectFromLoaderModule( const char * func ) 91 throw ( RuntimeException ) 92 { 93 PyRef object( PyDict_GetItemString(getLoaderModule().get(), (char*)func ) ); 94 if( !object.is() ) 95 { 96 OUStringBuffer buf; 97 buf.appendAscii( "pythonloader: couldn't find core element pythonloader." ); 98 buf.appendAscii( func ); 99 throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >()); 100 } 101 return object; 102 } 103 104 OUString getImplementationName() 105 { 106 return OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.pyuno.Loader" ) ); 107 } 108 109 Sequence< OUString > getSupportedServiceNames() 110 { 111 OUString serviceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.loader.Python" ) ); 112 return Sequence< OUString > ( &serviceName, 1 ); 113 } 114 115 static void setPythonHome ( const OUString & pythonHome ) 116 { 117 OUString systemPythonHome; 118 osl_getSystemPathFromFileURL( pythonHome.pData, &(systemPythonHome.pData) ); 119 OString o = rtl::OUStringToOString( systemPythonHome, osl_getThreadTextEncoding() ); 120 rtl_string_acquire(o.pData); // leak this string (thats the api!) 121 Py_SetPythonHome( o.pData->buffer); 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 PyEval_InitThreads(); 184 185 PyThreadState *tstate = PyThreadState_Get(); 186 PyEval_ReleaseThread( tstate ); 187 } 188 189 PyThreadAttach attach( PyInterpreterState_Head() ); 190 { 191 if( ! Runtime::isInitialized() ) 192 { 193 Runtime::initialize( ctx ); 194 } 195 Runtime runtime; 196 197 PyRef pyCtx = runtime.any2PyObject( 198 com::sun::star::uno::makeAny( ctx ) ); 199 200 PyRef clazz = getObjectFromLoaderModule( "Loader" ); 201 PyRef args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE ); 202 PyTuple_SetItem( args.get(), 0 , pyCtx.getAcquired() ); 203 PyRef pyInstance( PyObject_CallObject( clazz.get() , args.get() ), SAL_NO_ACQUIRE ); 204 runtime.pyObject2Any( pyInstance ) >>= ret; 205 } 206 return ret; 207 } 208 209 } 210 211 212 static struct cppu::ImplementationEntry g_entries[] = 213 { 214 { 215 pyuno_loader::CreateInstance, pyuno_loader::getImplementationName, 216 pyuno_loader::getSupportedServiceNames, cppu::createSingleComponentFactory, 217 0 , 0 218 }, 219 { 0, 0, 0, 0, 0, 0 } 220 }; 221 222 extern "C" 223 { 224 225 //================================================================================================== 226 void SAL_CALL component_getImplementationEnvironment( 227 const sal_Char ** ppEnvTypeName, uno_Environment ** ) 228 { 229 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 230 } 231 //================================================================================================== 232 void * SAL_CALL component_getFactory( 233 const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) 234 { 235 return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries ); 236 } 237 238 } 239 240