1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pyuno_loader.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <pyuno/pyuno.hxx>
33 #include <osl/process.h>
35 #include <osl/thread.h>
37 #include <rtl/ustrbuf.hxx>
38 #include <rtl/strbuf.hxx>
39 #include <rtl/bootstrap.hxx>
41 #include <cppuhelper/implementationentry.hxx>
42 #include <cppuhelper/factory.hxx>
45 using rtl::OUStringBuffer
;
50 using pyuno::PyThreadAttach
;
52 using com::sun::star::registry::XRegistryKey
;
53 using com::sun::star::uno::Reference
;
54 using com::sun::star::uno::XInterface
;
55 using com::sun::star::uno::Sequence
;
56 using com::sun::star::uno::XComponentContext
;
57 using com::sun::star::uno::RuntimeException
;
59 namespace pyuno_loader
62 static void raiseRuntimeExceptionWhenNeeded() throw ( RuntimeException
)
64 if( PyErr_Occurred() )
66 PyRef excType
, excValue
, excTraceback
;
67 PyErr_Fetch( (PyObject
**)&excType
, (PyObject
**)&excValue
,(PyObject
**)&excTraceback
);
69 com::sun::star::uno::Any a
= runtime
.extractUnoException( excType
, excValue
, excTraceback
);
71 buf
.appendAscii( "python-loader:" );
73 buf
.append( ((com::sun::star::uno::Exception
*)a
.getValue())->Message
);
74 throw RuntimeException( buf
.makeStringAndClear(), Reference
< XInterface
> () );
78 static PyRef
getLoaderModule() throw( RuntimeException
)
81 PyImport_ImportModule( const_cast< char * >("pythonloader") ),
83 raiseRuntimeExceptionWhenNeeded();
86 throw RuntimeException(
87 OUString( RTL_CONSTASCII_USTRINGPARAM( "pythonloader: Couldn't load pythonloader module" ) ),
88 Reference
< XInterface
> () );
90 return PyRef( PyModule_GetDict( module
.get() ));
93 static PyRef
getObjectFromLoaderModule( const char * func
)
94 throw ( RuntimeException
)
96 PyRef
object( PyDict_GetItemString(getLoaderModule().get(), (char*)func
) );
100 buf
.appendAscii( "pythonloader: couldn't find core element pythonloader." );
101 buf
.appendAscii( func
);
102 throw RuntimeException(buf
.makeStringAndClear(),Reference
< XInterface
>());
107 OUString
getImplementationName()
109 return OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.pyuno.Loader" ) );
112 Sequence
< OUString
> getSupportedServiceNames()
114 OUString
serviceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.loader.Python" ) );
115 return Sequence
< OUString
> ( &serviceName
, 1 );
118 static void setPythonHome ( const OUString
& pythonHome
)
120 OUString systemPythonHome
;
121 osl_getSystemPathFromFileURL( pythonHome
.pData
, &(systemPythonHome
.pData
) );
122 OString o
= rtl::OUStringToOString( systemPythonHome
, osl_getThreadTextEncoding() );
123 rtl_string_acquire(o
.pData
); // leak this string (thats the api!)
124 Py_SetPythonHome( o
.pData
->buffer
);
127 static void prependPythonPath( const OUString
& pythonPathBootstrap
)
129 rtl::OStringBuffer
bufPYTHONPATH( 256 );
130 bufPYTHONPATH
.append( "PYTHONPATH=");
131 sal_Int32 nIndex
= 0;
134 sal_Int32 nNew
= pythonPathBootstrap
.indexOf( ' ', nIndex
);
138 fileUrl
= OUString( &( pythonPathBootstrap
[nIndex
] ) );
142 fileUrl
= OUString( &(pythonPathBootstrap
[nIndex
]) , nNew
- nIndex
);
145 osl_getSystemPathFromFileURL( fileUrl
.pData
, &(systemPath
.pData
) );
146 bufPYTHONPATH
.append( rtl::OUStringToOString( systemPath
.pData
, osl_getThreadTextEncoding() ));
147 bufPYTHONPATH
.append( SAL_PATHSEPARATOR
);
152 const char * oldEnv
= getenv( "PYTHONPATH");
154 bufPYTHONPATH
.append( oldEnv
);
155 OString result
= bufPYTHONPATH
.makeStringAndClear();
156 rtl_string_acquire( result
.pData
);
158 // printf( "Setting %s\n" , result.pData->buffer );
159 putenv( result
.pData
->buffer
);
163 Reference
< XInterface
> CreateInstance( const Reference
< XComponentContext
> & ctx
)
165 Reference
< XInterface
> ret
;
167 if( ! Py_IsInitialized() )
171 OUString
path( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR/program/" SAL_CONFIGFILE("pythonloader.uno" )));
172 rtl::Bootstrap::expandMacros(path
); //TODO: detect failure
173 rtl::Bootstrap
bootstrap(path
);
175 // look for pythonhome
176 bootstrap
.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONHOME") ), pythonHome
);
177 bootstrap
.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONPATH" ) ) , pythonPath
);
179 // pythonhome+pythonpath must be set before Py_Initialize(), otherwise there appear warning on the console
180 // sadly, there is no api for setting the pythonpath, we have to use the environment variable
181 if( pythonHome
.getLength() )
182 setPythonHome( pythonHome
);
184 if( pythonPath
.getLength() )
185 prependPythonPath( pythonPath
);
189 PyEval_InitThreads();
191 PyThreadState
*tstate
= PyThreadState_Get();
192 PyEval_ReleaseThread( tstate
);
195 PyThreadAttach
attach( PyInterpreterState_Head() );
197 if( ! Runtime::isInitialized() )
199 Runtime::initialize( ctx
);
203 PyRef pyCtx
= runtime
.any2PyObject(
204 com::sun::star::uno::makeAny( ctx
) );
206 PyRef clazz
= getObjectFromLoaderModule( "Loader" );
207 PyRef
args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE
);
208 PyTuple_SetItem( args
.get(), 0 , pyCtx
.getAcquired() );
209 PyRef
pyInstance( PyObject_CallObject( clazz
.get() , args
.get() ), SAL_NO_ACQUIRE
);
210 runtime
.pyObject2Any( pyInstance
) >>= ret
;
218 static struct cppu::ImplementationEntry g_entries
[] =
221 pyuno_loader::CreateInstance
, pyuno_loader::getImplementationName
,
222 pyuno_loader::getSupportedServiceNames
, cppu::createSingleComponentFactory
,
231 //==================================================================================================
232 void SAL_CALL
component_getImplementationEnvironment(
233 const sal_Char
** ppEnvTypeName
, uno_Environment
** )
235 *ppEnvTypeName
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
;
237 //==================================================================================================
238 sal_Bool SAL_CALL
component_writeInfo(
239 void * pServiceManager
, void * pRegistryKey
)
241 return cppu::component_writeInfoHelper( pServiceManager
, pRegistryKey
, g_entries
);
243 //==================================================================================================
244 void * SAL_CALL
component_getFactory(
245 const sal_Char
* pImplName
, void * pServiceManager
, void * pRegistryKey
)
247 return cppu::component_getFactoryHelper( pImplName
, pServiceManager
, pRegistryKey
, g_entries
);