LCOV - code coverage report
Current view: top level - pyuno/source/module - pyuno_adapter.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 68 172 39.5 %
Date: 2015-06-13 12:38:46 Functions: 9 15 60.0 %
Legend: Lines: hit not hit

          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             : 
      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;
      46             : 
      47             : #define TO_ASCII(x) OUStringToOString( x , RTL_TEXTENCODING_ASCII_US).getStr()
      48             : 
      49             : namespace pyuno
      50             : {
      51             : 
      52          16 : Adapter::Adapter( const PyRef & ref, const Sequence< Type > &types )
      53             :     : mWrappedObject( ref ),
      54          16 :       mInterpreter( (PyThreadState_Get()->interp) ),
      55          32 :       mTypes( types )
      56          16 : {}
      57             : 
      58          48 : Adapter::~Adapter()
      59             : {
      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          16 :     decreaseRefCount( mInterpreter, mWrappedObject.get() );
      63          16 :     mWrappedObject.scratch();
      64          32 : }
      65             : 
      66           3 : static cppu::OImplementationId g_id( false );
      67             : 
      68         118 : Sequence<sal_Int8> Adapter::getUnoTunnelImplementationId()
      69             : {
      70         118 :     return g_id.getImplementationId();
      71             : }
      72             : 
      73           0 : sal_Int64 Adapter::getSomething( const Sequence< sal_Int8 > &id) throw (RuntimeException, std::exception)
      74             : {
      75           0 :     if( id == g_id.getImplementationId() )
      76           0 :         return reinterpret_cast<sal_Int64>(this);
      77           0 :     return 0;
      78             : }
      79             : 
      80         100 : void raiseInvocationTargetExceptionWhenNeeded( const Runtime &runtime )
      81             :     throw ( InvocationTargetException )
      82             : {
      83         100 :     if( PyErr_Occurred() )
      84             :     {
      85           0 :         PyRef excType, excValue, excTraceback;
      86           0 :         PyErr_Fetch(reinterpret_cast<PyObject **>(&excType), reinterpret_cast<PyObject**>(&excValue), reinterpret_cast<PyObject**>(&excTraceback));
      87           0 :         Any unoExc( runtime.extractUnoException( excType, excValue, excTraceback ) );
      88             :         throw InvocationTargetException(
      89           0 :             static_cast<com::sun::star::uno::Exception const *>(unoExc.getValue())->Message,
      90           0 :             Reference<XInterface>(), unoExc );
      91             :     }
      92         100 : }
      93             : 
      94           0 : Reference< XIntrospectionAccess > Adapter::getIntrospection()
      95             :     throw ( RuntimeException, std::exception )
      96             : {
      97             :     // not supported
      98           0 :     return Reference< XIntrospectionAccess > ();
      99             : }
     100             : 
     101           5 : Sequence< sal_Int16 > Adapter::getOutIndexes( const OUString & functionName )
     102             : {
     103           5 :     Sequence< sal_Int16 > ret;
     104           5 :     MethodOutIndexMap::const_iterator ii = m_methodOutIndexMap.find( functionName );
     105           5 :     if( ii == m_methodOutIndexMap.end() )
     106             :     {
     107             : 
     108           5 :         Runtime runtime;
     109             :         {
     110           5 :             PyThreadDetach antiguard;
     111             : 
     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          10 :                 runtime.getImpl()->cargo->xAdapterFactory->createAdapter( this, mTypes );
     116             : 
     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          10 :                 runtime.getImpl()->cargo->xIntrospection->inspect( makeAny( unoAdapterObject ) );
     122             : 
     123           5 :             if( !introspection.is() )
     124             :             {
     125             :                 throw RuntimeException(
     126           0 :                     "pyuno bridge: Couldn't inspect uno adapter ( the python class must implement com.sun.star.lang.XTypeProvider !)" );
     127             :             }
     128             : 
     129           5 :             Reference< XIdlMethod > method = introspection->getMethod(
     130          10 :                 functionName, com::sun::star::beans::MethodConcept::ALL );
     131           5 :             if( ! method.is( ) )
     132             :             {
     133             :                 throw RuntimeException(
     134           0 :                     "pyuno bridge: Couldn't get reflection for method " + functionName );
     135             :             }
     136             : 
     137          10 :             Sequence< ParamInfo > seqInfo = method->getParameterInfos();
     138             :             int i;
     139           5 :             int nOuts = 0;
     140           5 :             for( i = 0 ; i < seqInfo.getLength() ; i ++ )
     141             :             {
     142           0 :                 if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT ||
     143           0 :                     seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT )
     144             :                 {
     145             :                     // sequence must be interpreted as return value/outparameter tuple !
     146           0 :                     nOuts ++;
     147             :                 }
     148             :             }
     149             : 
     150           5 :             if( nOuts )
     151             :             {
     152           0 :                 ret.realloc( nOuts );
     153           0 :                 sal_Int32 nOutsAssigned = 0;
     154           0 :                 for( i = 0 ; i < seqInfo.getLength() ; i ++ )
     155             :                 {
     156           0 :                     if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT ||
     157           0 :                         seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT )
     158             :                     {
     159           0 :                         ret[nOutsAssigned] = (sal_Int16) i;
     160           0 :                         nOutsAssigned ++;
     161             :                     }
     162             :                 }
     163           5 :             }
     164             :         }
     165             :         // guard active again !
     166           5 :         m_methodOutIndexMap[ functionName ] = ret;
     167             :     }
     168             :     else
     169             :     {
     170           0 :         ret = ii->second;
     171             :     }
     172           5 :     return ret;
     173             : }
     174             : 
     175          34 : Any Adapter::invoke( const OUString &aFunctionName,
     176             :                      const Sequence< Any >& aParams,
     177             :                      Sequence< sal_Int16 > &aOutParamIndex,
     178             :                      Sequence< Any > &aOutParam)
     179             :     throw (IllegalArgumentException,CannotConvertException,InvocationTargetException,RuntimeException, std::exception)
     180             : {
     181          34 :     Any ret;
     182             : 
     183             :     // special hack for the uno object identity concept. The XUnoTunnel.getSomething() call is
     184             :     // always handled by the adapter directly.
     185          34 :     if( aParams.getLength() == 1 && aFunctionName == "getSomething" )
     186             :     {
     187           0 :         Sequence< sal_Int8 > id;
     188           0 :         if( aParams[0] >>= id )
     189           0 :             return com::sun::star::uno::makeAny( getSomething( id ) );
     190             : 
     191             :     }
     192             : 
     193          34 :     RuntimeCargo *cargo = 0;
     194             :     try
     195             :     {
     196          34 :     PyThreadAttach guard( mInterpreter );
     197             :     {
     198             :         // convert parameters to python args
     199             :         // TODO: Out parameter
     200          34 :         Runtime runtime;
     201          34 :         cargo = runtime.getImpl()->cargo;
     202          34 :         if( isLog( cargo, LogLevel::CALL ) )
     203             :         {
     204             :             logCall( cargo, "try     uno->py[0x",
     205           0 :                      mWrappedObject.get(), aFunctionName, aParams );
     206             :         }
     207             : 
     208          34 :         sal_Int32 size = aParams.getLength();
     209          68 :         PyRef argsTuple(PyTuple_New( size ), SAL_NO_ACQUIRE, NOT_NULL );
     210             :         int i;
     211             :         // fill tuple with default values in case of exceptions
     212          64 :         for(  i = 0 ;i < size ; i ++ )
     213             :         {
     214          30 :             Py_INCREF( Py_None );
     215          30 :             PyTuple_SetItem( argsTuple.get(), i, Py_None );
     216             :         }
     217             : 
     218             :         // convert args to python
     219          64 :         for( i = 0; i < size ; i ++  )
     220             :         {
     221          30 :             PyRef val = runtime.any2PyObject( aParams[i] );
     222          30 :             PyTuple_SetItem( argsTuple.get(), i, val.getAcquired() );
     223          30 :         }
     224             : 
     225             :         // get callable
     226             :         PyRef method(PyObject_GetAttrString( mWrappedObject.get(), TO_ASCII(aFunctionName)),
     227          68 :                      SAL_NO_ACQUIRE);
     228          34 :         raiseInvocationTargetExceptionWhenNeeded( runtime);
     229          34 :         if( !method.is() )
     230             :         {
     231           0 :             OUStringBuffer buf;
     232           0 :             buf.appendAscii( "pyuno::Adapater: Method " ).append( aFunctionName );
     233           0 :             buf.appendAscii( " is not implemented at object " );
     234           0 :             PyRef str( PyObject_Repr( mWrappedObject.get() ), SAL_NO_ACQUIRE );
     235           0 :             buf.append(pyString2ustring(str.get()));
     236           0 :             throw IllegalArgumentException( buf.makeStringAndClear(), Reference< XInterface > (),0 );
     237             :         }
     238             : 
     239          68 :         PyRef pyRet( PyObject_CallObject( method.get(), argsTuple.get() ), SAL_NO_ACQUIRE );
     240          34 :         raiseInvocationTargetExceptionWhenNeeded( runtime);
     241          34 :         if( pyRet.is() )
     242             :         {
     243          34 :             ret = runtime.pyObject2Any( pyRet );
     244             : 
     245          98 :             if( ret.hasValue() &&
     246          45 :                 ret.getValueTypeClass() == com::sun::star::uno::TypeClass_SEQUENCE &&
     247          54 :                 aFunctionName != "getTypes" &&  // needed by introspection itself !
     248           5 :                 aFunctionName != "getImplementationId" ) // needed by introspection itself !
     249             :             {
     250             :                 // the sequence can either be
     251             :                 // 1)  a simple sequence return value
     252             :                 // 2)  a sequence, where the first element is the return value
     253             :                 //     and the following elements are interpreted as the outparameter
     254             :                 // I can only decide for one solution by checking the method signature,
     255             :                 // so I need the reflection of the adapter !
     256           5 :                 aOutParamIndex = getOutIndexes( aFunctionName );
     257           5 :                 if( aOutParamIndex.getLength() )
     258             :                 {
     259             :                     // out parameters exist, extract the sequence
     260           0 :                     Sequence< Any  > seq;
     261           0 :                     if( ! ( ret >>= seq ) )
     262             :                     {
     263             :                         throw RuntimeException(
     264           0 :                             "pyuno bridge: Couldn't extract out parameters for method " + aFunctionName );
     265             :                     }
     266             : 
     267           0 :                     if( aOutParamIndex.getLength() +1 != seq.getLength() )
     268             :                     {
     269           0 :                         OUStringBuffer buf;
     270           0 :                         buf.append( "pyuno bridge: expected for method " );
     271           0 :                         buf.append( aFunctionName );
     272           0 :                         buf.append( " one return value and " );
     273           0 :                         buf.append( (sal_Int32) aOutParamIndex.getLength() );
     274           0 :                         buf.append( " out parameters, got a sequence of " );
     275           0 :                         buf.append( seq.getLength() );
     276           0 :                         buf.append( " elements as return value." );
     277           0 :                         throw RuntimeException(buf.makeStringAndClear(), *this );
     278             :                     }
     279             : 
     280           0 :                     aOutParam.realloc( aOutParamIndex.getLength() );
     281           0 :                     ret = seq[0];
     282           0 :                     for( i = 0 ; i < aOutParamIndex.getLength() ; i ++ )
     283             :                     {
     284           0 :                         aOutParam[i] = seq[1+i];
     285           0 :                     }
     286             :                 }
     287             :                 // else { sequence is a return value !}
     288             :             }
     289             :         }
     290             : 
     291             :         // log the reply, if desired
     292          34 :         if( isLog( cargo, LogLevel::CALL ) )
     293             :         {
     294             :             logReply( cargo, "success uno->py[0x" ,
     295           0 :                       mWrappedObject.get(), aFunctionName, ret, aOutParam );
     296          34 :         }
     297          34 :     }
     298             : 
     299             :     }
     300           0 :     catch( const InvocationTargetException & e )
     301             :     {
     302           0 :         if( isLog( cargo, LogLevel::CALL ) )
     303             :         {
     304             :             logException(
     305             :                 cargo, "except  uno->py[0x" ,
     306           0 :                 mWrappedObject.get(), aFunctionName,
     307           0 :                 e.TargetException.getValue(),e.TargetException.getValueType() );
     308             :         }
     309           0 :         throw;
     310             :     }
     311           0 :     catch( const IllegalArgumentException & e )
     312             :     {
     313           0 :         if( isLog( cargo, LogLevel::CALL ) )
     314             :         {
     315             :             logException(
     316             :                 cargo,  "except  uno->py[0x" ,
     317           0 :                 mWrappedObject.get(), aFunctionName, &e,cppu::UnoType<decltype(e)>::get() );
     318             :         }
     319           0 :         throw;
     320             :     }
     321           0 :     catch( const RuntimeException & e )
     322             :     {
     323           0 :         if( cargo && isLog( cargo, LogLevel::CALL ) )
     324             :         {
     325             :             logException(
     326             :                 cargo, "except  uno->py[0x" ,
     327           0 :                 mWrappedObject.get(), aFunctionName, &e,cppu::UnoType<decltype(e)>::get() );
     328             :         }
     329           0 :         throw;
     330             :     }
     331           0 :     catch( const CannotConvertException & e )
     332             :     {
     333           0 :         if( isLog( cargo, LogLevel::CALL ) )
     334             :         {
     335             :             logException(
     336             :                 cargo, "except  uno->py[0x" ,
     337           0 :                 mWrappedObject.get(), aFunctionName, &e,cppu::UnoType<decltype(e)>::get() );
     338             :         }
     339           0 :         throw;
     340             :     }
     341          34 :     return ret;
     342             : }
     343             : 
     344           0 : void Adapter::setValue( const OUString & aPropertyName, const Any & value )
     345             :     throw( UnknownPropertyException, CannotConvertException, InvocationTargetException,RuntimeException, std::exception)
     346             : {
     347           0 :     if( !hasProperty( aPropertyName ) )
     348             :     {
     349           0 :         OUStringBuffer buf;
     350           0 :         buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName );
     351           0 :         buf.appendAscii( " is unknown." );
     352           0 :         throw UnknownPropertyException( buf.makeStringAndClear() );
     353             :     }
     354             : 
     355           0 :     PyThreadAttach guard( mInterpreter );
     356             :     try
     357             :     {
     358           0 :         Runtime runtime;
     359           0 :         PyRef obj = runtime.any2PyObject( value );
     360             : 
     361             :         PyObject_SetAttrString(
     362           0 :             mWrappedObject.get(), TO_ASCII(aPropertyName), obj.get() );
     363           0 :         raiseInvocationTargetExceptionWhenNeeded( runtime);
     364             : 
     365             :     }
     366           0 :     catch( const IllegalArgumentException & exc )
     367             :     {
     368           0 :         throw InvocationTargetException( exc.Message, *this, com::sun::star::uno::makeAny( exc ) );
     369           0 :     }
     370           0 : }
     371             : 
     372           0 : Any Adapter::getValue( const OUString & aPropertyName )
     373             :     throw ( UnknownPropertyException, RuntimeException, std::exception )
     374             : {
     375           0 :     Any ret;
     376           0 :     PyThreadAttach guard( mInterpreter );
     377             :     {
     378           0 :         Runtime runtime;
     379             :         PyRef pyRef(
     380             :             PyObject_GetAttrString( mWrappedObject.get(), TO_ASCII(aPropertyName) ),
     381           0 :             SAL_NO_ACQUIRE );
     382             : 
     383           0 :         if (!pyRef.is() || PyErr_Occurred())
     384             :         {
     385           0 :             OUStringBuffer buf;
     386           0 :             buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName );
     387           0 :             buf.appendAscii( " is unknown." );
     388           0 :             throw UnknownPropertyException( buf.makeStringAndClear() );
     389             :         }
     390           0 :         ret = runtime.pyObject2Any( pyRef );
     391             :     }
     392           0 :     return ret;
     393             : }
     394             : 
     395           0 : sal_Bool Adapter::hasMethod( const OUString & aMethodName )
     396             :     throw ( RuntimeException, std::exception )
     397             : {
     398           0 :     return hasProperty( aMethodName );
     399             : }
     400             : 
     401           0 : sal_Bool Adapter::hasProperty( const OUString & aPropertyName )
     402             :     throw ( RuntimeException, std::exception )
     403             : {
     404           0 :     bool bRet = false;
     405           0 :     PyThreadAttach guard( mInterpreter );
     406             :     {
     407             :         bRet = PyObject_HasAttrString(
     408           0 :             mWrappedObject.get() , TO_ASCII( aPropertyName ));
     409             :     }
     410           0 :     return bRet;
     411             : }
     412             : 
     413           9 : }
     414             : 
     415             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11