Update ooo320-m1
[ooovba.git] / pyuno / source / module / pyuno_adapter.cxx
blob8c678142988c659b9585abbc4a8aae1e61b47f75
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pyuno_adapter.cxx,v $
10 * $Revision: 1.10 $
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 ************************************************************************/
30 #include "pyuno_impl.hxx"
32 #include <rtl/ustrbuf.hxx>
33 #include <rtl/strbuf.hxx>
35 #include <com/sun/star/beans/MethodConcept.hpp>
37 #include <cppuhelper/typeprovider.hxx>
39 using rtl::OUStringToOString;
40 using rtl::OUString;
41 using rtl::OUStringBuffer;
42 using rtl::OString;
43 using rtl::OStringBuffer;
45 using com::sun::star::beans::XIntrospectionAccess;
46 using com::sun::star::beans::XIntrospection;
47 using com::sun::star::uno::Any;
48 using com::sun::star::uno::makeAny;
49 using com::sun::star::uno::Reference;
50 using com::sun::star::uno::Sequence;
51 using com::sun::star::uno::RuntimeException;
52 using com::sun::star::uno::XInterface;
53 using com::sun::star::uno::Type;
54 using com::sun::star::lang::XUnoTunnel;
55 using com::sun::star::lang::IllegalArgumentException;
56 using com::sun::star::beans::UnknownPropertyException;
57 using com::sun::star::script::CannotConvertException;
58 using com::sun::star::reflection::InvocationTargetException;
59 using com::sun::star::reflection::XIdlMethod;
60 using com::sun::star::reflection::ParamInfo;
61 using com::sun::star::reflection::XIdlClass;
63 #define TO_ASCII(x) OUStringToOString( x , RTL_TEXTENCODING_ASCII_US).getStr()
65 namespace pyuno
68 Adapter::Adapter( const PyRef & ref, const Sequence< Type > &types )
69 : mWrappedObject( ref ),
70 mInterpreter( (PyThreadState_Get()->interp) ),
71 mTypes( types )
74 Adapter::~Adapter()
76 // Problem: We don't know, if we have the python interpreter lock
77 // There is no runtime function to get to know this.
78 decreaseRefCount( mInterpreter, mWrappedObject.get() );
79 mWrappedObject.scratch();
82 static cppu::OImplementationId g_id( sal_False );
84 Sequence<sal_Int8> Adapter::getUnoTunnelImplementationId()
86 return g_id.getImplementationId();
89 sal_Int64 Adapter::getSomething( const Sequence< sal_Int8 > &id) throw (RuntimeException)
91 if( id == g_id.getImplementationId() )
92 return reinterpret_cast<sal_Int64>(this);
93 return 0;
96 void raiseInvocationTargetExceptionWhenNeeded( const Runtime &runtime )
97 throw ( InvocationTargetException )
99 if( PyErr_Occurred() )
101 PyRef excType, excValue, excTraceback;
102 PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
103 Any unoExc( runtime.extractUnoException( excType, excValue, excTraceback ) );
104 throw InvocationTargetException(
105 ((com::sun::star::uno::Exception*)unoExc.getValue())->Message,
106 Reference<XInterface>(), unoExc );
110 Reference< XIntrospectionAccess > Adapter::getIntrospection()
111 throw ( RuntimeException )
113 // not supported
114 return Reference< XIntrospectionAccess > ();
117 Sequence< sal_Int16 > Adapter::getOutIndexes( const OUString & functionName )
119 Sequence< sal_Int16 > ret;
120 MethodOutIndexMap::const_iterator ii = m_methodOutIndexMap.find( functionName );
121 if( ii == m_methodOutIndexMap.end() )
124 Runtime runtime;
126 PyThreadDetach antiguard;
128 // retrieve the adapter object again. It will be the same instance as before,
129 // (the adapter factory keeps a weak map inside, which I couldn't have outside)
130 Reference< XInterface > unoAdapterObject =
131 runtime.getImpl()->cargo->xAdapterFactory->createAdapter( this, mTypes );
133 // uuuh, that's really expensive. The alternative would have been, to store
134 // an instance of the introspection at (this), but this results in a cyclic
135 // reference, which is never broken (as it is up to OOo1.1.0).
136 Reference< XIntrospectionAccess > introspection =
137 runtime.getImpl()->cargo->xIntrospection->inspect( makeAny( unoAdapterObject ) );
139 if( !introspection.is() )
141 throw RuntimeException(
142 OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno bridge: Couldn't inspect uno adapter ( the python class must implement com.sun.star.lang.XTypeProvider !)" ) ),
143 Reference< XInterface > () );
146 Reference< XIdlMethod > method = introspection->getMethod(
147 functionName, com::sun::star::beans::MethodConcept::ALL );
148 if( ! method.is( ) )
150 throw RuntimeException(
151 (OUString(
152 RTL_CONSTASCII_USTRINGPARAM(
153 "pyuno bridge: Couldn't get reflection for method "))
154 + functionName),
155 Reference< XInterface > () );
158 Sequence< ParamInfo > seqInfo = method->getParameterInfos();
159 int i;
160 int nOuts = 0;
161 for( i = 0 ; i < seqInfo.getLength() ; i ++ )
163 if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT ||
164 seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT )
166 // sequence must be interpreted as return value/outparameter tuple !
167 nOuts ++;
171 if( nOuts )
173 ret.realloc( nOuts );
174 sal_Int32 nOutsAssigned = 0;
175 for( i = 0 ; i < seqInfo.getLength() ; i ++ )
177 if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT ||
178 seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT )
180 ret[nOutsAssigned] = (sal_Int16) i;
181 nOutsAssigned ++;
186 // guard active again !
187 m_methodOutIndexMap[ functionName ] = ret;
189 else
191 ret = ii->second;
193 return ret;
196 Any Adapter::invoke( const OUString &aFunctionName,
197 const Sequence< Any >& aParams,
198 Sequence< sal_Int16 > &aOutParamIndex,
199 Sequence< Any > &aOutParam)
200 throw (IllegalArgumentException,CannotConvertException,InvocationTargetException,RuntimeException)
202 Any ret;
204 // special hack for the uno object identity concept. The XUnoTunnel.getSomething() call is
205 // always handled by the adapter directly.
206 if( aParams.getLength() == 1 && 0 == aFunctionName.compareToAscii( "getSomething" ) )
208 Sequence< sal_Int8 > id;
209 if( aParams[0] >>= id )
210 return com::sun::star::uno::makeAny( getSomething( id ) );
214 RuntimeCargo *cargo = 0;
217 PyThreadAttach guard( mInterpreter );
219 // convert parameters to python args
220 // TODO: Out parameter
221 Runtime runtime;
222 cargo = runtime.getImpl()->cargo;
223 if( isLog( cargo, LogLevel::CALL ) )
225 logCall( cargo, "try uno->py[0x",
226 mWrappedObject.get(), aFunctionName, aParams );
229 sal_Int32 size = aParams.getLength();
230 PyRef argsTuple(PyTuple_New( size ), SAL_NO_ACQUIRE );
231 int i;
232 // fill tuple with default values in case of exceptions
233 for( i = 0 ;i < size ; i ++ )
235 Py_INCREF( Py_None );
236 PyTuple_SetItem( argsTuple.get(), i, Py_None );
239 // convert args to python
240 for( i = 0; i < size ; i ++ )
242 PyRef val = runtime.any2PyObject( aParams[i] );
243 PyTuple_SetItem( argsTuple.get(), i, val.getAcquired() );
246 // get callable
247 PyRef method(PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aFunctionName)),
248 SAL_NO_ACQUIRE);
249 raiseInvocationTargetExceptionWhenNeeded( runtime);
250 if( !method.is() )
252 OUStringBuffer buf;
253 buf.appendAscii( "pyuno::Adapater: Method " ).append( aFunctionName );
254 buf.appendAscii( " is not implemented at object " );
255 PyRef str( PyObject_Repr( mWrappedObject.get() ), SAL_NO_ACQUIRE );
256 buf.appendAscii( PyString_AsString( str.get() ));
257 throw IllegalArgumentException( buf.makeStringAndClear(), Reference< XInterface > (),0 );
260 PyRef pyRet( PyObject_CallObject( method.get(), argsTuple.get() ), SAL_NO_ACQUIRE );
261 raiseInvocationTargetExceptionWhenNeeded( runtime);
262 if( pyRet.is() )
264 ret = runtime.pyObject2Any( pyRet );
266 if( ret.hasValue() &&
267 ret.getValueTypeClass() == com::sun::star::uno::TypeClass_SEQUENCE &&
268 0 != aFunctionName.compareToAscii( "getTypes" ) && // needed by introspection itself !
269 0 != aFunctionName.compareToAscii( "getImplementationId" ) ) // needed by introspection itself !
271 // the sequence can either be
272 // 1) a simple sequence return value
273 // 2) a sequence, where the first element is the return value
274 // and the following elements are interpreted as the outparameter
275 // I can only decide for one solution by checking the method signature,
276 // so I need the reflection of the adapter !
277 aOutParamIndex = getOutIndexes( aFunctionName );
278 if( aOutParamIndex.getLength() )
280 // out parameters exist, extract the sequence
281 Sequence< Any > seq;
282 if( ! ( ret >>= seq ) )
284 throw RuntimeException(
285 (OUString(
286 RTL_CONSTASCII_USTRINGPARAM(
287 "pyuno bridge: Couldn't extract out"
288 " parameters for method "))
289 + aFunctionName),
290 Reference< XInterface > () );
293 if( aOutParamIndex.getLength() +1 != seq.getLength() )
295 OUStringBuffer buf;
296 buf.appendAscii( "pyuno bridge: expected for method " );
297 buf.append( aFunctionName );
298 buf.appendAscii( " one return value and " );
299 buf.append( (sal_Int32) aOutParamIndex.getLength() );
300 buf.appendAscii( " out parameters, got a sequence of " );
301 buf.append( seq.getLength() );
302 buf.appendAscii( " elements as return value." );
303 throw RuntimeException(buf.makeStringAndClear(), *this );
306 aOutParam.realloc( aOutParamIndex.getLength() );
307 ret = seq[0];
308 for( i = 0 ; i < aOutParamIndex.getLength() ; i ++ )
310 aOutParam[i] = seq[1+i];
313 // else { sequence is a return value !}
317 // log the reply, if desired
318 if( isLog( cargo, LogLevel::CALL ) )
320 logReply( cargo, "success uno->py[0x" ,
321 mWrappedObject.get(), aFunctionName, ret, aOutParam );
326 catch(InvocationTargetException & e )
328 if( isLog( cargo, LogLevel::CALL ) )
330 logException(
331 cargo, "except uno->py[0x" ,
332 mWrappedObject.get(), aFunctionName,
333 e.TargetException.getValue(),e.TargetException.getValueType() );
335 throw;
337 catch( RuntimeException & e )
339 if( cargo && isLog( cargo, LogLevel::CALL ) )
341 logException(
342 cargo, "except uno->py[0x" ,
343 mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
345 throw;
347 catch( CannotConvertException & e )
349 if( isLog( cargo, LogLevel::CALL ) )
351 logException(
352 cargo, "except uno->py[0x" ,
353 mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
355 throw;
357 catch( IllegalArgumentException & e )
359 if( isLog( cargo, LogLevel::CALL ) )
361 logException(
362 cargo, "except uno->py[0x" ,
363 mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
365 throw;
367 return ret;
370 void Adapter::setValue( const OUString & aPropertyName, const Any & value )
371 throw( UnknownPropertyException, CannotConvertException, InvocationTargetException,RuntimeException)
373 PyThreadAttach guard( mInterpreter );
376 Runtime runtime;
377 PyRef obj = runtime.any2PyObject( value );
379 if( !hasProperty( aPropertyName ) )
381 OUStringBuffer buf;
382 buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName );
383 buf.appendAscii( " is unknown." );
384 throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () );
387 PyObject_SetAttrString(
388 mWrappedObject.get(), (char*)TO_ASCII(aPropertyName), obj.get() );
389 raiseInvocationTargetExceptionWhenNeeded( runtime);
392 catch( IllegalArgumentException & exc )
394 throw InvocationTargetException( exc.Message, *this, com::sun::star::uno::makeAny( exc ) );
398 Any Adapter::getValue( const OUString & aPropertyName )
399 throw ( UnknownPropertyException, RuntimeException )
401 Any ret;
402 PyThreadAttach guard( mInterpreter );
404 Runtime runtime;
405 PyRef pyRef(
406 PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aPropertyName) ),
407 SAL_NO_ACQUIRE );
409 raiseInvocationTargetExceptionWhenNeeded( runtime);
410 if( !pyRef.is() )
412 OUStringBuffer buf;
413 buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName );
414 buf.appendAscii( " is unknown." );
415 throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () );
417 ret = runtime.pyObject2Any( pyRef );
419 return ret;
422 sal_Bool Adapter::hasMethod( const OUString & aMethodName )
423 throw ( RuntimeException )
425 return hasProperty( aMethodName );
428 sal_Bool Adapter::hasProperty( const OUString & aPropertyName )
429 throw ( RuntimeException )
431 bool bRet = false;
432 PyThreadAttach guard( mInterpreter );
434 bRet = PyObject_HasAttrString(
435 mWrappedObject.get() , (char*) TO_ASCII( aPropertyName ));
437 return bRet;