1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include <pyuno/pyuno.hxx>
29*cdf0e10cSrcweir 
30*cdf0e10cSrcweir #include <osl/process.h>
31*cdf0e10cSrcweir #include <osl/file.h>
32*cdf0e10cSrcweir #include <osl/thread.h>
33*cdf0e10cSrcweir 
34*cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
35*cdf0e10cSrcweir #include <rtl/strbuf.hxx>
36*cdf0e10cSrcweir #include <rtl/bootstrap.hxx>
37*cdf0e10cSrcweir 
38*cdf0e10cSrcweir #include <cppuhelper/implementationentry.hxx>
39*cdf0e10cSrcweir #include <cppuhelper/factory.hxx>
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir using rtl::OUString;
42*cdf0e10cSrcweir using rtl::OUStringBuffer;
43*cdf0e10cSrcweir using rtl::OString;
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir using pyuno::PyRef;
46*cdf0e10cSrcweir using pyuno::Runtime;
47*cdf0e10cSrcweir using pyuno::PyThreadAttach;
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir using com::sun::star::registry::XRegistryKey;
50*cdf0e10cSrcweir using com::sun::star::uno::Reference;
51*cdf0e10cSrcweir using com::sun::star::uno::XInterface;
52*cdf0e10cSrcweir using com::sun::star::uno::Sequence;
53*cdf0e10cSrcweir using com::sun::star::uno::XComponentContext;
54*cdf0e10cSrcweir using com::sun::star::uno::RuntimeException;
55*cdf0e10cSrcweir 
56*cdf0e10cSrcweir namespace pyuno_loader
57*cdf0e10cSrcweir {
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir static void raiseRuntimeExceptionWhenNeeded() throw ( RuntimeException )
60*cdf0e10cSrcweir {
61*cdf0e10cSrcweir     if( PyErr_Occurred() )
62*cdf0e10cSrcweir     {
63*cdf0e10cSrcweir         PyRef excType, excValue, excTraceback;
64*cdf0e10cSrcweir         PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
65*cdf0e10cSrcweir         Runtime runtime;
66*cdf0e10cSrcweir         com::sun::star::uno::Any a = runtime.extractUnoException( excType, excValue, excTraceback );
67*cdf0e10cSrcweir         OUStringBuffer buf;
68*cdf0e10cSrcweir         buf.appendAscii( "python-loader:" );
69*cdf0e10cSrcweir         if( a.hasValue() )
70*cdf0e10cSrcweir             buf.append( ((com::sun::star::uno::Exception *)a.getValue())->Message );
71*cdf0e10cSrcweir         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () );
72*cdf0e10cSrcweir     }
73*cdf0e10cSrcweir }
74*cdf0e10cSrcweir 
75*cdf0e10cSrcweir static PyRef getLoaderModule() throw( RuntimeException )
76*cdf0e10cSrcweir {
77*cdf0e10cSrcweir     PyRef module(
78*cdf0e10cSrcweir         PyImport_ImportModule( const_cast< char * >("pythonloader") ),
79*cdf0e10cSrcweir         SAL_NO_ACQUIRE );
80*cdf0e10cSrcweir     raiseRuntimeExceptionWhenNeeded();
81*cdf0e10cSrcweir     if( !module.is() )
82*cdf0e10cSrcweir     {
83*cdf0e10cSrcweir         throw RuntimeException(
84*cdf0e10cSrcweir             OUString( RTL_CONSTASCII_USTRINGPARAM( "pythonloader: Couldn't load pythonloader module" ) ),
85*cdf0e10cSrcweir             Reference< XInterface > () );
86*cdf0e10cSrcweir     }
87*cdf0e10cSrcweir     return PyRef( PyModule_GetDict( module.get() ));
88*cdf0e10cSrcweir }
89*cdf0e10cSrcweir 
90*cdf0e10cSrcweir static PyRef getObjectFromLoaderModule( const char * func )
91*cdf0e10cSrcweir     throw ( RuntimeException )
92*cdf0e10cSrcweir {
93*cdf0e10cSrcweir     PyRef object( PyDict_GetItemString(getLoaderModule().get(), (char*)func ) );
94*cdf0e10cSrcweir     if( !object.is() )
95*cdf0e10cSrcweir     {
96*cdf0e10cSrcweir         OUStringBuffer buf;
97*cdf0e10cSrcweir         buf.appendAscii( "pythonloader: couldn't find core element pythonloader." );
98*cdf0e10cSrcweir         buf.appendAscii( func );
99*cdf0e10cSrcweir         throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >());
100*cdf0e10cSrcweir     }
101*cdf0e10cSrcweir     return object;
102*cdf0e10cSrcweir }
103*cdf0e10cSrcweir 
104*cdf0e10cSrcweir OUString getImplementationName()
105*cdf0e10cSrcweir {
106*cdf0e10cSrcweir     return OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.pyuno.Loader" ) );
107*cdf0e10cSrcweir }
108*cdf0e10cSrcweir 
109*cdf0e10cSrcweir Sequence< OUString > getSupportedServiceNames()
110*cdf0e10cSrcweir {
111*cdf0e10cSrcweir     OUString serviceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.loader.Python" ) );
112*cdf0e10cSrcweir     return Sequence< OUString > ( &serviceName, 1 );
113*cdf0e10cSrcweir }
114*cdf0e10cSrcweir 
115*cdf0e10cSrcweir static void setPythonHome ( const OUString & pythonHome )
116*cdf0e10cSrcweir {
117*cdf0e10cSrcweir     OUString systemPythonHome;
118*cdf0e10cSrcweir     osl_getSystemPathFromFileURL( pythonHome.pData, &(systemPythonHome.pData) );
119*cdf0e10cSrcweir     OString o = rtl::OUStringToOString( systemPythonHome, osl_getThreadTextEncoding() );
120*cdf0e10cSrcweir     rtl_string_acquire(o.pData); // leak this string (thats the api!)
121*cdf0e10cSrcweir     Py_SetPythonHome( o.pData->buffer);
122*cdf0e10cSrcweir }
123*cdf0e10cSrcweir 
124*cdf0e10cSrcweir static void prependPythonPath( const OUString & pythonPathBootstrap )
125*cdf0e10cSrcweir {
126*cdf0e10cSrcweir     rtl::OUStringBuffer bufPYTHONPATH( 256 );
127*cdf0e10cSrcweir     sal_Int32 nIndex = 0;
128*cdf0e10cSrcweir     while( 1 )
129*cdf0e10cSrcweir     {
130*cdf0e10cSrcweir         sal_Int32 nNew = pythonPathBootstrap.indexOf( ' ', nIndex );
131*cdf0e10cSrcweir         OUString fileUrl;
132*cdf0e10cSrcweir         if( nNew == -1 )
133*cdf0e10cSrcweir         {
134*cdf0e10cSrcweir             fileUrl = OUString( &( pythonPathBootstrap[nIndex] ) );
135*cdf0e10cSrcweir         }
136*cdf0e10cSrcweir         else
137*cdf0e10cSrcweir         {
138*cdf0e10cSrcweir             fileUrl = OUString( &(pythonPathBootstrap[nIndex]) , nNew - nIndex );
139*cdf0e10cSrcweir         }
140*cdf0e10cSrcweir         OUString systemPath;
141*cdf0e10cSrcweir         osl_getSystemPathFromFileURL( fileUrl.pData, &(systemPath.pData) );
142*cdf0e10cSrcweir         bufPYTHONPATH.append( systemPath );
143*cdf0e10cSrcweir         bufPYTHONPATH.append( static_cast<sal_Unicode>(SAL_PATHSEPARATOR) );
144*cdf0e10cSrcweir         if( nNew == -1 )
145*cdf0e10cSrcweir             break;
146*cdf0e10cSrcweir         nIndex = nNew + 1;
147*cdf0e10cSrcweir     }
148*cdf0e10cSrcweir     const char * oldEnv = getenv( "PYTHONPATH");
149*cdf0e10cSrcweir     if( oldEnv )
150*cdf0e10cSrcweir         bufPYTHONPATH.append( rtl::OUString(oldEnv, strlen(oldEnv), osl_getThreadTextEncoding()) );
151*cdf0e10cSrcweir 
152*cdf0e10cSrcweir     rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("PYTHONPATH"));
153*cdf0e10cSrcweir     rtl::OUString envValue(bufPYTHONPATH.makeStringAndClear());
154*cdf0e10cSrcweir     osl_setEnvironment(envVar.pData, envValue.pData);
155*cdf0e10cSrcweir }
156*cdf0e10cSrcweir 
157*cdf0e10cSrcweir Reference< XInterface > CreateInstance( const Reference< XComponentContext > & ctx )
158*cdf0e10cSrcweir {
159*cdf0e10cSrcweir     Reference< XInterface > ret;
160*cdf0e10cSrcweir 
161*cdf0e10cSrcweir     if( ! Py_IsInitialized() )
162*cdf0e10cSrcweir     {
163*cdf0e10cSrcweir         OUString pythonPath;
164*cdf0e10cSrcweir         OUString pythonHome;
165*cdf0e10cSrcweir         OUString path( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR/program/" SAL_CONFIGFILE("pythonloader.uno" )));
166*cdf0e10cSrcweir         rtl::Bootstrap::expandMacros(path); //TODO: detect failure
167*cdf0e10cSrcweir         rtl::Bootstrap bootstrap(path);
168*cdf0e10cSrcweir 
169*cdf0e10cSrcweir         // look for pythonhome
170*cdf0e10cSrcweir         bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONHOME") ), pythonHome );
171*cdf0e10cSrcweir         bootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "PYUNO_LOADER_PYTHONPATH" ) ) , pythonPath );
172*cdf0e10cSrcweir 
173*cdf0e10cSrcweir         // pythonhome+pythonpath must be set before Py_Initialize(), otherwise there appear warning on the console
174*cdf0e10cSrcweir         // sadly, there is no api for setting the pythonpath, we have to use the environment variable
175*cdf0e10cSrcweir         if( pythonHome.getLength() )
176*cdf0e10cSrcweir             setPythonHome( pythonHome );
177*cdf0e10cSrcweir 
178*cdf0e10cSrcweir         if( pythonPath.getLength() )
179*cdf0e10cSrcweir             prependPythonPath( pythonPath );
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir         // initialize python
182*cdf0e10cSrcweir         Py_Initialize();
183*cdf0e10cSrcweir         PyEval_InitThreads();
184*cdf0e10cSrcweir 
185*cdf0e10cSrcweir         PyThreadState *tstate = PyThreadState_Get();
186*cdf0e10cSrcweir         PyEval_ReleaseThread( tstate );
187*cdf0e10cSrcweir     }
188*cdf0e10cSrcweir 
189*cdf0e10cSrcweir     PyThreadAttach attach( PyInterpreterState_Head() );
190*cdf0e10cSrcweir     {
191*cdf0e10cSrcweir         if( ! Runtime::isInitialized() )
192*cdf0e10cSrcweir         {
193*cdf0e10cSrcweir             Runtime::initialize( ctx );
194*cdf0e10cSrcweir         }
195*cdf0e10cSrcweir         Runtime runtime;
196*cdf0e10cSrcweir 
197*cdf0e10cSrcweir         PyRef pyCtx = runtime.any2PyObject(
198*cdf0e10cSrcweir             com::sun::star::uno::makeAny( ctx ) );
199*cdf0e10cSrcweir 
200*cdf0e10cSrcweir         PyRef clazz = getObjectFromLoaderModule( "Loader" );
201*cdf0e10cSrcweir         PyRef args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE );
202*cdf0e10cSrcweir         PyTuple_SetItem( args.get(), 0 , pyCtx.getAcquired() );
203*cdf0e10cSrcweir         PyRef pyInstance( PyObject_CallObject( clazz.get() , args.get() ), SAL_NO_ACQUIRE );
204*cdf0e10cSrcweir         runtime.pyObject2Any( pyInstance ) >>= ret;
205*cdf0e10cSrcweir     }
206*cdf0e10cSrcweir     return ret;
207*cdf0e10cSrcweir }
208*cdf0e10cSrcweir 
209*cdf0e10cSrcweir }
210*cdf0e10cSrcweir 
211*cdf0e10cSrcweir 
212*cdf0e10cSrcweir static struct cppu::ImplementationEntry g_entries[] =
213*cdf0e10cSrcweir {
214*cdf0e10cSrcweir 	{
215*cdf0e10cSrcweir 		pyuno_loader::CreateInstance, pyuno_loader::getImplementationName,
216*cdf0e10cSrcweir 		pyuno_loader::getSupportedServiceNames, cppu::createSingleComponentFactory,
217*cdf0e10cSrcweir 		0 , 0
218*cdf0e10cSrcweir 	},
219*cdf0e10cSrcweir 	{ 0, 0, 0, 0, 0, 0 }
220*cdf0e10cSrcweir };
221*cdf0e10cSrcweir 
222*cdf0e10cSrcweir extern "C"
223*cdf0e10cSrcweir {
224*cdf0e10cSrcweir 
225*cdf0e10cSrcweir //==================================================================================================
226*cdf0e10cSrcweir void SAL_CALL component_getImplementationEnvironment(
227*cdf0e10cSrcweir 	const sal_Char ** ppEnvTypeName, uno_Environment ** )
228*cdf0e10cSrcweir {
229*cdf0e10cSrcweir 	*ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
230*cdf0e10cSrcweir }
231*cdf0e10cSrcweir //==================================================================================================
232*cdf0e10cSrcweir void * SAL_CALL component_getFactory(
233*cdf0e10cSrcweir 	const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
234*cdf0e10cSrcweir {
235*cdf0e10cSrcweir 	return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
236*cdf0e10cSrcweir }
237*cdf0e10cSrcweir 
238*cdf0e10cSrcweir }
239*cdf0e10cSrcweir 
240