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

Generated by: LCOV version 1.10