Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : : #include "pyuno_impl.hxx"
20 : :
21 : : #include <rtl/ustrbuf.hxx>
22 : : #include <rtl/strbuf.hxx>
23 : :
24 : : #include <com/sun/star/beans/MethodConcept.hpp>
25 : :
26 : : #include <cppuhelper/typeprovider.hxx>
27 : :
28 : : using rtl::OUStringToOString;
29 : : using rtl::OUString;
30 : : using rtl::OUStringBuffer;
31 : : using rtl::OString;
32 : : using rtl::OStringBuffer;
33 : :
34 : : using com::sun::star::beans::XIntrospectionAccess;
35 : : using com::sun::star::beans::XIntrospection;
36 : : using com::sun::star::uno::Any;
37 : : using com::sun::star::uno::makeAny;
38 : : using com::sun::star::uno::Reference;
39 : : using com::sun::star::uno::Sequence;
40 : : using com::sun::star::uno::RuntimeException;
41 : : using com::sun::star::uno::XInterface;
42 : : using com::sun::star::uno::Type;
43 : : using com::sun::star::lang::XUnoTunnel;
44 : : using com::sun::star::lang::IllegalArgumentException;
45 : : using com::sun::star::beans::UnknownPropertyException;
46 : : using com::sun::star::script::CannotConvertException;
47 : : using com::sun::star::reflection::InvocationTargetException;
48 : : using com::sun::star::reflection::XIdlMethod;
49 : : using com::sun::star::reflection::ParamInfo;
50 : : using com::sun::star::reflection::XIdlClass;
51 : :
52 : : #define TO_ASCII(x) OUStringToOString( x , RTL_TEXTENCODING_ASCII_US).getStr()
53 : :
54 : : namespace pyuno
55 : : {
56 : :
57 : 356 : Adapter::Adapter( const PyRef & ref, const Sequence< Type > &types )
58 : : : mWrappedObject( ref ),
59 [ + - ]: 356 : mInterpreter( (PyThreadState_Get()->interp) ),
60 [ + - ][ + - ]: 712 : mTypes( types )
[ + - ]
61 : 356 : {}
62 : :
63 [ + - ][ + - ]: 356 : Adapter::~Adapter()
[ + - ]
64 : : {
65 : : // Problem: We don't know, if we have the python interpreter lock
66 : : // There is no runtime function to get to know this.
67 [ + - ]: 356 : decreaseRefCount( mInterpreter, mWrappedObject.get() );
68 : 356 : mWrappedObject.scratch();
69 [ - + ]: 712 : }
70 : :
71 : 112 : static cppu::OImplementationId g_id( sal_False );
72 : :
73 : 4759 : Sequence<sal_Int8> Adapter::getUnoTunnelImplementationId()
74 : : {
75 : 4759 : return g_id.getImplementationId();
76 : : }
77 : :
78 : 4629 : sal_Int64 Adapter::getSomething( const Sequence< sal_Int8 > &id) throw (RuntimeException)
79 : : {
80 [ + - ][ + - ]: 4629 : if( id == g_id.getImplementationId() )
81 : 4629 : return reinterpret_cast<sal_Int64>(this);
82 : 4629 : return 0;
83 : : }
84 : :
85 : 11320 : void raiseInvocationTargetExceptionWhenNeeded( const Runtime &runtime )
86 : : throw ( InvocationTargetException )
87 : : {
88 [ - + ]: 11320 : if( PyErr_Occurred() )
89 : : {
90 : 0 : PyRef excType, excValue, excTraceback;
91 [ # # ]: 0 : PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
92 [ # # ]: 0 : Any unoExc( runtime.extractUnoException( excType, excValue, excTraceback ) );
93 : : throw InvocationTargetException(
94 : 0 : ((com::sun::star::uno::Exception*)unoExc.getValue())->Message,
95 [ # # ]: 0 : Reference<XInterface>(), unoExc );
96 : : }
97 : 11320 : }
98 : :
99 : 0 : Reference< XIntrospectionAccess > Adapter::getIntrospection()
100 : : throw ( RuntimeException )
101 : : {
102 : : // not supported
103 : 0 : return Reference< XIntrospectionAccess > ();
104 : : }
105 : :
106 : 96 : Sequence< sal_Int16 > Adapter::getOutIndexes( const OUString & functionName )
107 : : {
108 [ + - ]: 96 : Sequence< sal_Int16 > ret;
109 [ + - ]: 96 : MethodOutIndexMap::const_iterator ii = m_methodOutIndexMap.find( functionName );
110 [ + - ][ + - ]: 96 : if( ii == m_methodOutIndexMap.end() )
111 : : {
112 : :
113 [ + - ]: 96 : Runtime runtime;
114 : : {
115 [ + - ]: 96 : PyThreadDetach antiguard;
116 : :
117 : : // retrieve the adapter object again. It will be the same instance as before,
118 : : // (the adapter factory keeps a weak map inside, which I couldn't have outside)
119 : : Reference< XInterface > unoAdapterObject =
120 [ + - ][ + - ]: 96 : runtime.getImpl()->cargo->xAdapterFactory->createAdapter( this, mTypes );
[ + - ]
121 : :
122 : : // uuuh, that's really expensive. The alternative would have been, to store
123 : : // an instance of the introspection at (this), but this results in a cyclic
124 : : // reference, which is never broken (as it is up to OOo1.1.0).
125 : : Reference< XIntrospectionAccess > introspection =
126 [ + - ][ + - ]: 96 : runtime.getImpl()->cargo->xIntrospection->inspect( makeAny( unoAdapterObject ) );
[ + - ]
127 : :
128 [ - + ]: 96 : if( !introspection.is() )
129 : : {
130 : : throw RuntimeException(
131 : : OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno bridge: Couldn't inspect uno adapter ( the python class must implement com.sun.star.lang.XTypeProvider !)" ) ),
132 [ # # ][ # # ]: 0 : Reference< XInterface > () );
133 : : }
134 : :
135 [ + - ]: 96 : Reference< XIdlMethod > method = introspection->getMethod(
136 [ + - ]: 96 : functionName, com::sun::star::beans::MethodConcept::ALL );
137 [ - + ]: 96 : if( ! method.is( ) )
138 : : {
139 : : throw RuntimeException(
140 : : (OUString(
141 : : RTL_CONSTASCII_USTRINGPARAM(
142 : : "pyuno bridge: Couldn't get reflection for method "))
143 : : + functionName),
144 [ # # ][ # # ]: 0 : Reference< XInterface > () );
145 : : }
146 : :
147 [ + - ][ + - ]: 96 : Sequence< ParamInfo > seqInfo = method->getParameterInfos();
148 : : int i;
149 : 96 : int nOuts = 0;
150 [ - + ]: 96 : for( i = 0 ; i < seqInfo.getLength() ; i ++ )
151 : : {
152 [ # # ][ # # ]: 0 : if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT ||
[ # # ][ # # ]
153 [ # # ]: 0 : seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT )
154 : : {
155 : : // sequence must be interpreted as return value/outparameter tuple !
156 : 0 : nOuts ++;
157 : : }
158 : : }
159 : :
160 [ - + ]: 96 : if( nOuts )
161 : : {
162 [ # # ]: 0 : ret.realloc( nOuts );
163 : 0 : sal_Int32 nOutsAssigned = 0;
164 [ # # ]: 0 : for( i = 0 ; i < seqInfo.getLength() ; i ++ )
165 : : {
166 [ # # ][ # # ]: 0 : if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT ||
[ # # ][ # # ]
167 [ # # ]: 0 : seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT )
168 : : {
169 [ # # ]: 0 : ret[nOutsAssigned] = (sal_Int16) i;
170 : 0 : nOutsAssigned ++;
171 : : }
172 : : }
173 [ + - ][ + - ]: 96 : }
174 : : }
175 : : // guard active again !
176 [ + - ][ + - ]: 96 : m_methodOutIndexMap[ functionName ] = ret;
[ + - ]
177 : : }
178 : : else
179 : : {
180 [ # # ][ # # ]: 96 : ret = ii->second;
181 : : }
182 : 96 : return ret;
183 : : }
184 : :
185 : 5304 : Any Adapter::invoke( const OUString &aFunctionName,
186 : : const Sequence< Any >& aParams,
187 : : Sequence< sal_Int16 > &aOutParamIndex,
188 : : Sequence< Any > &aOutParam)
189 : : throw (IllegalArgumentException,CannotConvertException,InvocationTargetException,RuntimeException)
190 : : {
191 : 5304 : Any ret;
192 : :
193 : : // special hack for the uno object identity concept. The XUnoTunnel.getSomething() call is
194 : : // always handled by the adapter directly.
195 [ - + ][ - + ]: 5304 : if( aParams.getLength() == 1 && 0 == aFunctionName.compareToAscii( "getSomething" ) )
[ + + ]
196 : : {
197 [ # # ]: 0 : Sequence< sal_Int8 > id;
198 [ # # ][ # # ]: 0 : if( aParams[0] >>= id )
199 [ # # ][ # # ]: 0 : return com::sun::star::uno::makeAny( getSomething( id ) );
[ # # ][ # # ]
200 : :
201 : : }
202 : :
203 : 5304 : RuntimeCargo *cargo = 0;
204 : : try
205 : : {
206 [ + - ]: 5304 : PyThreadAttach guard( mInterpreter );
207 : : {
208 : : // convert parameters to python args
209 : : // TODO: Out parameter
210 [ + - ]: 5304 : Runtime runtime;
211 : 5304 : cargo = runtime.getImpl()->cargo;
212 [ - + ][ + - ]: 5304 : if( isLog( cargo, LogLevel::CALL ) )
213 : : {
214 : : logCall( cargo, "try uno->py[0x",
215 [ # # ]: 0 : mWrappedObject.get(), aFunctionName, aParams );
216 : : }
217 : :
218 : 5304 : sal_Int32 size = aParams.getLength();
219 [ + - ]: 5304 : PyRef argsTuple(PyTuple_New( size ), SAL_NO_ACQUIRE );
220 : : int i;
221 : : // fill tuple with default values in case of exceptions
222 [ + + ]: 33866 : for( i = 0 ;i < size ; i ++ )
223 : : {
224 : 28562 : Py_INCREF( Py_None );
225 [ + - ]: 28562 : PyTuple_SetItem( argsTuple.get(), i, Py_None );
226 : : }
227 : :
228 : : // convert args to python
229 [ + + ]: 33866 : for( i = 0; i < size ; i ++ )
230 : : {
231 [ + - ]: 28562 : PyRef val = runtime.any2PyObject( aParams[i] );
232 [ + - ]: 28562 : PyTuple_SetItem( argsTuple.get(), i, val.getAcquired() );
233 [ + - ]: 28562 : }
234 : :
235 : : // get callable
236 [ + - ]: 10608 : PyRef method(PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aFunctionName)),
237 [ + - ]: 5304 : SAL_NO_ACQUIRE);
238 [ + - ]: 5304 : raiseInvocationTargetExceptionWhenNeeded( runtime);
239 [ - + ]: 5304 : if( !method.is() )
240 : : {
241 : 0 : OUStringBuffer buf;
242 [ # # ][ # # ]: 0 : buf.appendAscii( "pyuno::Adapater: Method " ).append( aFunctionName );
243 [ # # ]: 0 : buf.appendAscii( " is not implemented at object " );
244 [ # # ]: 0 : PyRef str( PyObject_Repr( mWrappedObject.get() ), SAL_NO_ACQUIRE );
245 [ # # ][ # # ]: 0 : buf.appendAscii( PyString_AsString( str.get() ));
246 [ # # ][ # # ]: 0 : throw IllegalArgumentException( buf.makeStringAndClear(), Reference< XInterface > (),0 );
247 : : }
248 : :
249 [ + - ]: 5304 : PyRef pyRet( PyObject_CallObject( method.get(), argsTuple.get() ), SAL_NO_ACQUIRE );
250 [ + - ]: 5304 : raiseInvocationTargetExceptionWhenNeeded( runtime);
251 [ + - ]: 5304 : if( pyRet.is() )
252 : : {
253 [ + - ]: 5304 : ret = runtime.pyObject2Any( pyRet );
254 : :
255 [ + + ][ + - : 11088 : if( ret.hasValue() &&
+ + + + +
+ ]
256 : 5304 : ret.getValueTypeClass() == com::sun::star::uno::TypeClass_SEQUENCE &&
257 : 288 : 0 != aFunctionName.compareToAscii( "getTypes" ) && // needed by introspection itself !
258 : 192 : 0 != aFunctionName.compareToAscii( "getImplementationId" ) ) // needed by introspection itself !
259 : : {
260 : : // the sequence can either be
261 : : // 1) a simple sequence return value
262 : : // 2) a sequence, where the first element is the return value
263 : : // and the following elements are interpreted as the outparameter
264 : : // I can only decide for one solution by checking the method signature,
265 : : // so I need the reflection of the adapter !
266 [ + - ][ + - ]: 96 : aOutParamIndex = getOutIndexes( aFunctionName );
[ + - ]
267 [ - + ]: 96 : if( aOutParamIndex.getLength() )
268 : : {
269 : : // out parameters exist, extract the sequence
270 [ # # ]: 0 : Sequence< Any > seq;
271 [ # # ][ # # ]: 0 : if( ! ( ret >>= seq ) )
272 : : {
273 : : throw RuntimeException(
274 : : (OUString(
275 : : RTL_CONSTASCII_USTRINGPARAM(
276 : : "pyuno bridge: Couldn't extract out"
277 : : " parameters for method "))
278 : : + aFunctionName),
279 [ # # ][ # # ]: 0 : Reference< XInterface > () );
280 : : }
281 : :
282 [ # # ]: 0 : if( aOutParamIndex.getLength() +1 != seq.getLength() )
283 : : {
284 : 0 : OUStringBuffer buf;
285 [ # # ]: 0 : buf.appendAscii( "pyuno bridge: expected for method " );
286 [ # # ]: 0 : buf.append( aFunctionName );
287 [ # # ]: 0 : buf.appendAscii( " one return value and " );
288 [ # # ]: 0 : buf.append( (sal_Int32) aOutParamIndex.getLength() );
289 [ # # ]: 0 : buf.appendAscii( " out parameters, got a sequence of " );
290 [ # # ]: 0 : buf.append( seq.getLength() );
291 [ # # ]: 0 : buf.appendAscii( " elements as return value." );
292 [ # # ][ # # ]: 0 : throw RuntimeException(buf.makeStringAndClear(), *this );
[ # # ]
293 : : }
294 : :
295 [ # # ]: 0 : aOutParam.realloc( aOutParamIndex.getLength() );
296 [ # # ]: 0 : ret = seq[0];
297 [ # # ]: 0 : for( i = 0 ; i < aOutParamIndex.getLength() ; i ++ )
298 : : {
299 [ # # ][ # # ]: 0 : aOutParam[i] = seq[1+i];
300 [ # # ]: 0 : }
301 : : }
302 : : // else { sequence is a return value !}
303 : : }
304 : : }
305 : :
306 : : // log the reply, if desired
307 [ + - ][ - + ]: 5304 : if( isLog( cargo, LogLevel::CALL ) )
308 : : {
309 : : logReply( cargo, "success uno->py[0x" ,
310 [ # # ]: 0 : mWrappedObject.get(), aFunctionName, ret, aOutParam );
311 [ + - ][ + - ]: 5304 : }
[ + - ][ + - ]
312 [ + - ]: 5304 : }
313 : :
314 : : }
315 : 0 : catch( const InvocationTargetException & e )
316 : : {
317 [ # # # # ]: 0 : if( isLog( cargo, LogLevel::CALL ) )
318 : : {
319 : : logException(
320 : : cargo, "except uno->py[0x" ,
321 : 0 : mWrappedObject.get(), aFunctionName,
322 [ # # ]: 0 : e.TargetException.getValue(),e.TargetException.getValueType() );
323 : : }
324 : 0 : throw;
325 : : }
326 : 0 : catch( const RuntimeException & e )
327 : : {
328 [ # # # # : 0 : if( cargo && isLog( cargo, LogLevel::CALL ) )
# # # # ]
329 : : {
330 : : logException(
331 : : cargo, "except uno->py[0x" ,
332 [ # # # # ]: 0 : mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
333 : : }
334 : 0 : throw;
335 : : }
336 : 0 : catch( const CannotConvertException & e )
337 : : {
338 [ # # # # ]: 0 : if( isLog( cargo, LogLevel::CALL ) )
339 : : {
340 : : logException(
341 : : cargo, "except uno->py[0x" ,
342 [ # # # # ]: 0 : mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
343 : : }
344 : 0 : throw;
345 : : }
346 [ # # # # : 0 : catch( const IllegalArgumentException & e )
# ]
347 : : {
348 [ # # # # ]: 0 : if( isLog( cargo, LogLevel::CALL ) )
349 : : {
350 : : logException(
351 : : cargo, "except uno->py[0x" ,
352 [ # # # # ]: 0 : mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
353 : : }
354 : 0 : throw;
355 : : }
356 : 5304 : return ret;
357 : : }
358 : :
359 : 0 : void Adapter::setValue( const OUString & aPropertyName, const Any & value )
360 : : throw( UnknownPropertyException, CannotConvertException, InvocationTargetException,RuntimeException)
361 : : {
362 [ # # ]: 0 : PyThreadAttach guard( mInterpreter );
363 : : try
364 : : {
365 [ # # ]: 0 : Runtime runtime;
366 [ # # ]: 0 : PyRef obj = runtime.any2PyObject( value );
367 : :
368 [ # # ][ # # ]: 0 : if( !hasProperty( aPropertyName ) )
369 : : {
370 : 0 : OUStringBuffer buf;
371 [ # # ][ # # ]: 0 : buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName );
372 [ # # ]: 0 : buf.appendAscii( " is unknown." );
373 [ # # ][ # # ]: 0 : throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () );
374 : : }
375 : :
376 : : PyObject_SetAttrString(
377 [ # # ][ # # ]: 0 : mWrappedObject.get(), (char*)TO_ASCII(aPropertyName), obj.get() );
378 [ # # ][ # # ]: 0 : raiseInvocationTargetExceptionWhenNeeded( runtime);
[ # # ]
379 : :
380 : : }
381 [ # # ]: 0 : catch( const IllegalArgumentException & exc )
382 : : {
383 [ # # # # : 0 : throw InvocationTargetException( exc.Message, *this, com::sun::star::uno::makeAny( exc ) );
# # ]
384 [ # # ]: 0 : }
385 : 0 : }
386 : :
387 : 0 : Any Adapter::getValue( const OUString & aPropertyName )
388 : : throw ( UnknownPropertyException, RuntimeException )
389 : : {
390 : 0 : Any ret;
391 [ # # ]: 0 : PyThreadAttach guard( mInterpreter );
392 : : {
393 [ # # ]: 0 : Runtime runtime;
394 : : PyRef pyRef(
395 [ # # ]: 0 : PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aPropertyName) ),
396 [ # # ]: 0 : SAL_NO_ACQUIRE );
397 : :
398 [ # # ]: 0 : raiseInvocationTargetExceptionWhenNeeded( runtime);
399 [ # # ]: 0 : if( !pyRef.is() )
400 : : {
401 : 0 : OUStringBuffer buf;
402 [ # # ][ # # ]: 0 : buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName );
403 [ # # ]: 0 : buf.appendAscii( " is unknown." );
404 [ # # ][ # # ]: 0 : throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () );
405 : : }
406 [ # # ][ # # ]: 0 : ret = runtime.pyObject2Any( pyRef );
[ # # ]
407 : : }
408 [ # # ]: 0 : return ret;
409 : : }
410 : :
411 : 0 : sal_Bool Adapter::hasMethod( const OUString & aMethodName )
412 : : throw ( RuntimeException )
413 : : {
414 : 0 : return hasProperty( aMethodName );
415 : : }
416 : :
417 : 0 : sal_Bool Adapter::hasProperty( const OUString & aPropertyName )
418 : : throw ( RuntimeException )
419 : : {
420 : 0 : bool bRet = false;
421 [ # # ]: 0 : PyThreadAttach guard( mInterpreter );
422 : : {
423 : : bRet = PyObject_HasAttrString(
424 [ # # ][ # # ]: 0 : mWrappedObject.get() , (char*) TO_ASCII( aPropertyName ));
425 : : }
426 [ # # ]: 0 : return bRet;
427 : : }
428 : :
429 [ + - ][ + - ]: 336 : }
430 : :
431 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|