bump product version to 4.1.6.2
[LibreOffice.git] / pyuno / source / module / pyuno_adapter.cxx
blobb51bc06912d062ec3b3d99086e6540f5148561c1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #include "pyuno_impl.hxx"
21 #include <rtl/ustrbuf.hxx>
22 #include <rtl/strbuf.hxx>
24 #include <com/sun/star/beans/MethodConcept.hpp>
26 #include <cppuhelper/typeprovider.hxx>
29 using com::sun::star::beans::XIntrospectionAccess;
30 using com::sun::star::beans::XIntrospection;
31 using com::sun::star::uno::Any;
32 using com::sun::star::uno::makeAny;
33 using com::sun::star::uno::Reference;
34 using com::sun::star::uno::Sequence;
35 using com::sun::star::uno::RuntimeException;
36 using com::sun::star::uno::XInterface;
37 using com::sun::star::uno::Type;
38 using com::sun::star::lang::XUnoTunnel;
39 using com::sun::star::lang::IllegalArgumentException;
40 using com::sun::star::beans::UnknownPropertyException;
41 using com::sun::star::script::CannotConvertException;
42 using com::sun::star::reflection::InvocationTargetException;
43 using com::sun::star::reflection::XIdlMethod;
44 using com::sun::star::reflection::ParamInfo;
45 using com::sun::star::reflection::XIdlClass;
47 #define TO_ASCII(x) OUStringToOString( x , RTL_TEXTENCODING_ASCII_US).getStr()
49 namespace pyuno
52 Adapter::Adapter( const PyRef & ref, const Sequence< Type > &types )
53 : mWrappedObject( ref ),
54 mInterpreter( (PyThreadState_Get()->interp) ),
55 mTypes( types )
58 Adapter::~Adapter()
60 // Problem: We don't know, if we have the python interpreter lock
61 // There is no runtime function to get to know this.
62 decreaseRefCount( mInterpreter, mWrappedObject.get() );
63 mWrappedObject.scratch();
66 static cppu::OImplementationId g_id( sal_False );
68 Sequence<sal_Int8> Adapter::getUnoTunnelImplementationId()
70 return g_id.getImplementationId();
73 sal_Int64 Adapter::getSomething( const Sequence< sal_Int8 > &id) throw (RuntimeException)
75 if( id == g_id.getImplementationId() )
76 return reinterpret_cast<sal_Int64>(this);
77 return 0;
80 void raiseInvocationTargetExceptionWhenNeeded( const Runtime &runtime )
81 throw ( InvocationTargetException )
83 if( PyErr_Occurred() )
85 PyRef excType, excValue, excTraceback;
86 PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
87 Any unoExc( runtime.extractUnoException( excType, excValue, excTraceback ) );
88 throw InvocationTargetException(
89 ((com::sun::star::uno::Exception*)unoExc.getValue())->Message,
90 Reference<XInterface>(), unoExc );
94 Reference< XIntrospectionAccess > Adapter::getIntrospection()
95 throw ( RuntimeException )
97 // not supported
98 return Reference< XIntrospectionAccess > ();
101 Sequence< sal_Int16 > Adapter::getOutIndexes( const OUString & functionName )
103 Sequence< sal_Int16 > ret;
104 MethodOutIndexMap::const_iterator ii = m_methodOutIndexMap.find( functionName );
105 if( ii == m_methodOutIndexMap.end() )
108 Runtime runtime;
110 PyThreadDetach antiguard;
112 // retrieve the adapter object again. It will be the same instance as before,
113 // (the adapter factory keeps a weak map inside, which I couldn't have outside)
114 Reference< XInterface > unoAdapterObject =
115 runtime.getImpl()->cargo->xAdapterFactory->createAdapter( this, mTypes );
117 // uuuh, that's really expensive. The alternative would have been, to store
118 // an instance of the introspection at (this), but this results in a cyclic
119 // reference, which is never broken (as it is up to OOo1.1.0).
120 Reference< XIntrospectionAccess > introspection =
121 runtime.getImpl()->cargo->xIntrospection->inspect( makeAny( unoAdapterObject ) );
123 if( !introspection.is() )
125 throw RuntimeException(
126 OUString( "pyuno bridge: Couldn't inspect uno adapter ( the python class must implement com.sun.star.lang.XTypeProvider !)" ),
127 Reference< XInterface > () );
130 Reference< XIdlMethod > method = introspection->getMethod(
131 functionName, com::sun::star::beans::MethodConcept::ALL );
132 if( ! method.is( ) )
134 throw RuntimeException(
135 (OUString(
136 "pyuno bridge: Couldn't get reflection for method ")
137 + functionName),
138 Reference< XInterface > () );
141 Sequence< ParamInfo > seqInfo = method->getParameterInfos();
142 int i;
143 int nOuts = 0;
144 for( i = 0 ; i < seqInfo.getLength() ; i ++ )
146 if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT ||
147 seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT )
149 // sequence must be interpreted as return value/outparameter tuple !
150 nOuts ++;
154 if( nOuts )
156 ret.realloc( nOuts );
157 sal_Int32 nOutsAssigned = 0;
158 for( i = 0 ; i < seqInfo.getLength() ; i ++ )
160 if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT ||
161 seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT )
163 ret[nOutsAssigned] = (sal_Int16) i;
164 nOutsAssigned ++;
169 // guard active again !
170 m_methodOutIndexMap[ functionName ] = ret;
172 else
174 ret = ii->second;
176 return ret;
179 Any Adapter::invoke( const OUString &aFunctionName,
180 const Sequence< Any >& aParams,
181 Sequence< sal_Int16 > &aOutParamIndex,
182 Sequence< Any > &aOutParam)
183 throw (IllegalArgumentException,CannotConvertException,InvocationTargetException,RuntimeException)
185 Any ret;
187 // special hack for the uno object identity concept. The XUnoTunnel.getSomething() call is
188 // always handled by the adapter directly.
189 if( aParams.getLength() == 1 && 0 == aFunctionName.compareToAscii( "getSomething" ) )
191 Sequence< sal_Int8 > id;
192 if( aParams[0] >>= id )
193 return com::sun::star::uno::makeAny( getSomething( id ) );
197 RuntimeCargo *cargo = 0;
200 PyThreadAttach guard( mInterpreter );
202 // convert parameters to python args
203 // TODO: Out parameter
204 Runtime runtime;
205 cargo = runtime.getImpl()->cargo;
206 if( isLog( cargo, LogLevel::CALL ) )
208 logCall( cargo, "try uno->py[0x",
209 mWrappedObject.get(), aFunctionName, aParams );
212 sal_Int32 size = aParams.getLength();
213 PyRef argsTuple(PyTuple_New( size ), SAL_NO_ACQUIRE );
214 int i;
215 // fill tuple with default values in case of exceptions
216 for( i = 0 ;i < size ; i ++ )
218 Py_INCREF( Py_None );
219 PyTuple_SetItem( argsTuple.get(), i, Py_None );
222 // convert args to python
223 for( i = 0; i < size ; i ++ )
225 PyRef val = runtime.any2PyObject( aParams[i] );
226 PyTuple_SetItem( argsTuple.get(), i, val.getAcquired() );
229 // get callable
230 PyRef method(PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aFunctionName)),
231 SAL_NO_ACQUIRE);
232 raiseInvocationTargetExceptionWhenNeeded( runtime);
233 if( !method.is() )
235 OUStringBuffer buf;
236 buf.appendAscii( "pyuno::Adapater: Method " ).append( aFunctionName );
237 buf.appendAscii( " is not implemented at object " );
238 PyRef str( PyObject_Repr( mWrappedObject.get() ), SAL_NO_ACQUIRE );
239 buf.append(pyString2ustring(str.get()));
240 throw IllegalArgumentException( buf.makeStringAndClear(), Reference< XInterface > (),0 );
243 PyRef pyRet( PyObject_CallObject( method.get(), argsTuple.get() ), SAL_NO_ACQUIRE );
244 raiseInvocationTargetExceptionWhenNeeded( runtime);
245 if( pyRet.is() )
247 ret = runtime.pyObject2Any( pyRet );
249 if( ret.hasValue() &&
250 ret.getValueTypeClass() == com::sun::star::uno::TypeClass_SEQUENCE &&
251 0 != aFunctionName.compareToAscii( "getTypes" ) && // needed by introspection itself !
252 0 != aFunctionName.compareToAscii( "getImplementationId" ) ) // needed by introspection itself !
254 // the sequence can either be
255 // 1) a simple sequence return value
256 // 2) a sequence, where the first element is the return value
257 // and the following elements are interpreted as the outparameter
258 // I can only decide for one solution by checking the method signature,
259 // so I need the reflection of the adapter !
260 aOutParamIndex = getOutIndexes( aFunctionName );
261 if( aOutParamIndex.getLength() )
263 // out parameters exist, extract the sequence
264 Sequence< Any > seq;
265 if( ! ( ret >>= seq ) )
267 throw RuntimeException(
268 (OUString("pyuno bridge: Couldn't extract out"
269 " parameters for method ")
270 + aFunctionName),
271 Reference< XInterface > () );
274 if( aOutParamIndex.getLength() +1 != seq.getLength() )
276 OUStringBuffer buf;
277 buf.append( "pyuno bridge: expected for method " );
278 buf.append( aFunctionName );
279 buf.append( " one return value and " );
280 buf.append( (sal_Int32) aOutParamIndex.getLength() );
281 buf.append( " out parameters, got a sequence of " );
282 buf.append( seq.getLength() );
283 buf.append( " elements as return value." );
284 throw RuntimeException(buf.makeStringAndClear(), *this );
287 aOutParam.realloc( aOutParamIndex.getLength() );
288 ret = seq[0];
289 for( i = 0 ; i < aOutParamIndex.getLength() ; i ++ )
291 aOutParam[i] = seq[1+i];
294 // else { sequence is a return value !}
298 // log the reply, if desired
299 if( isLog( cargo, LogLevel::CALL ) )
301 logReply( cargo, "success uno->py[0x" ,
302 mWrappedObject.get(), aFunctionName, ret, aOutParam );
307 catch( const InvocationTargetException & e )
309 if( isLog( cargo, LogLevel::CALL ) )
311 logException(
312 cargo, "except uno->py[0x" ,
313 mWrappedObject.get(), aFunctionName,
314 e.TargetException.getValue(),e.TargetException.getValueType() );
316 throw;
318 catch( const IllegalArgumentException & e )
320 if( isLog( cargo, LogLevel::CALL ) )
322 logException(
323 cargo, "except uno->py[0x" ,
324 mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
326 throw;
328 catch( const RuntimeException & e )
330 if( cargo && isLog( cargo, LogLevel::CALL ) )
332 logException(
333 cargo, "except uno->py[0x" ,
334 mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
336 throw;
338 catch( const CannotConvertException & e )
340 if( isLog( cargo, LogLevel::CALL ) )
342 logException(
343 cargo, "except uno->py[0x" ,
344 mWrappedObject.get(), aFunctionName, &e,getCppuType(&e) );
346 throw;
348 return ret;
351 void Adapter::setValue( const OUString & aPropertyName, const Any & value )
352 throw( UnknownPropertyException, CannotConvertException, InvocationTargetException,RuntimeException)
354 if( !hasProperty( aPropertyName ) )
356 OUStringBuffer buf;
357 buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName );
358 buf.appendAscii( " is unknown." );
359 throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () );
362 PyThreadAttach guard( mInterpreter );
365 Runtime runtime;
366 PyRef obj = runtime.any2PyObject( value );
368 PyObject_SetAttrString(
369 mWrappedObject.get(), (char*)TO_ASCII(aPropertyName), obj.get() );
370 raiseInvocationTargetExceptionWhenNeeded( runtime);
373 catch( const IllegalArgumentException & exc )
375 throw InvocationTargetException( exc.Message, *this, com::sun::star::uno::makeAny( exc ) );
379 Any Adapter::getValue( const OUString & aPropertyName )
380 throw ( UnknownPropertyException, RuntimeException )
382 Any ret;
383 PyThreadAttach guard( mInterpreter );
385 Runtime runtime;
386 PyRef pyRef(
387 PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aPropertyName) ),
388 SAL_NO_ACQUIRE );
390 raiseInvocationTargetExceptionWhenNeeded( runtime);
391 if( !pyRef.is() )
393 OUStringBuffer buf;
394 buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName );
395 buf.appendAscii( " is unknown." );
396 throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () );
398 ret = runtime.pyObject2Any( pyRef );
400 return ret;
403 sal_Bool Adapter::hasMethod( const OUString & aMethodName )
404 throw ( RuntimeException )
406 return hasProperty( aMethodName );
409 sal_Bool Adapter::hasProperty( const OUString & aPropertyName )
410 throw ( RuntimeException )
412 bool bRet = false;
413 PyThreadAttach guard( mInterpreter );
415 bRet = PyObject_HasAttrString(
416 mWrappedObject.get() , (char*) TO_ASCII( aPropertyName ));
418 return bRet;
423 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */