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