diff options
author | Jörg Budischewski <jbu@openoffice.org> | 2003-03-23 11:12:59 +0000 |
---|---|---|
committer | Jörg Budischewski <jbu@openoffice.org> | 2003-03-23 11:12:59 +0000 |
commit | e80bdbafeba9af9b58aac81b999f4b299c9eecd6 (patch) | |
tree | cfdc28280badab993505bbb4950633a026d526ca /pyuno/source/module/pyuno_adapter.cxx | |
parent | 479dc59b5cc884f3dd8c3f8e0bd955e6bcaebfa7 (diff) |
initial checkin for the pyuno-0.9.2 release
Diffstat (limited to 'pyuno/source/module/pyuno_adapter.cxx')
-rw-r--r-- | pyuno/source/module/pyuno_adapter.cxx | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/pyuno/source/module/pyuno_adapter.cxx b/pyuno/source/module/pyuno_adapter.cxx new file mode 100644 index 000000000000..3176b3caa60b --- /dev/null +++ b/pyuno/source/module/pyuno_adapter.cxx @@ -0,0 +1,406 @@ +/************************************************************************* + * + * $RCSfile: pyuno_adapter.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: jbu $ $Date: 2003-03-23 12:12:56 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Ralph Thomas + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Ralph Thomas, Joerg Budischewski + * + * + ************************************************************************/ +#include "pyuno_impl.hxx" + +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> + +#include <com/sun/star/beans/MethodConcept.hpp> + +#include <cppuhelper/typeprovider.hxx> + +using rtl::OUStringToOString; +using rtl::OUString; +using rtl::OUStringBuffer; +using rtl::OString; +using rtl::OStringBuffer; + +using com::sun::star::beans::XIntrospectionAccess; +using com::sun::star::beans::XIntrospection; +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::XInterface; +using com::sun::star::lang::XUnoTunnel; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::beans::UnknownPropertyException; +using com::sun::star::script::CannotConvertException; +using com::sun::star::reflection::InvocationTargetException; +using com::sun::star::reflection::XIdlMethod; +using com::sun::star::reflection::ParamInfo; +using com::sun::star::reflection::XIdlClass; + +#define TO_ASCII(x) OUStringToOString( x , RTL_TEXTENCODING_ASCII_US).getStr() + +namespace pyuno +{ + +Adapter::Adapter( const PyRef & ref, const Runtime & runtime): + mWrappedObject( ref ), mInterpreter( (PyThreadState_Get()->interp) ) +{} + +Adapter::~Adapter() +{ + // Problem: We don't know, if we have the python interpreter lock + // There is no runtime function to get to know this. + decreaseRefCount( mInterpreter, mWrappedObject.get() ); + mWrappedObject.scratch(); +} + +static cppu::OImplementationId g_id( sal_False ); + +Sequence<sal_Int8> Adapter::getUnoTunnelImplementationId() +{ + return g_id.getImplementationId(); +} + +sal_Int64 Adapter::getSomething( const Sequence< sal_Int8 > &id) throw (RuntimeException) +{ + if( id == g_id.getImplementationId() ) + return (sal_Int64)this; + return 0; +} + +void raiseInvocationTargetExceptionWhenNeeded( const Runtime &runtime ) + throw ( InvocationTargetException ) +{ + if( PyErr_Occurred() ) + { + PyRef excType, excValue, excTraceback; + PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback); + Any unoExc = runtime.pyObject2Any( excValue ); + PyRef str( PyObject_Repr( excTraceback.get() ), SAL_NO_ACQUIRE ); + if( unoExc.getValueTypeClass() != com::sun::star::uno::TypeClass_EXCEPTION ) + { + OUStringBuffer buf; + buf.appendAscii( "python object raised an unknown exception (" ); + PyRef valueRep( PyObject_Repr( excValue.get() ), SAL_NO_ACQUIRE ); + buf.appendAscii( PyString_AsString( valueRep.get())).appendAscii( ", traceback follows\n" ); + buf.appendAscii( PyString_AsString( str.get() ) ); + RuntimeException e; + e.Message = buf.makeStringAndClear(); + unoExc = makeAny( e ); + } + com::sun::star::uno::Exception e; + unoExc >>= e; + + OUStringBuffer buf; + buf.append( ((com::sun::star::uno::Exception*)unoExc.getValue())->Message ); + buf.appendAscii( "pyuno-bridge:" ); + buf.append( e.Message ); + buf.appendAscii( "," ); + buf.appendAscii( PyString_AsString( str.get() ) ); + + OUString msg = buf.makeStringAndClear(); + ((com::sun::star::uno::Exception*)unoExc.getValue())->Message = msg; + throw InvocationTargetException(msg, Reference<XInterface>(), unoExc ); + } +} + +Reference< XIntrospectionAccess > Adapter::getIntrospection() + throw ( RuntimeException ) +{ + // not supported + return Reference< XIntrospectionAccess > (); +} + +Any Adapter::invoke( const OUString &aFunctionName, + const Sequence< Any >& aParams, + Sequence< sal_Int16 > &aOutParamIndex, + Sequence< Any > &aOutParam) + throw (IllegalArgumentException,CannotConvertException,InvocationTargetException,RuntimeException) +{ + Any ret; + PyThreadAttach guard( mInterpreter ); + { + // convert parameters to python args + // TODO: Out parameter + Runtime runtime; + + sal_Int32 size = aParams.getLength(); + PyRef argsTuple(PyTuple_New( size ), SAL_NO_ACQUIRE ); + int i; + // fill tuple with default values in case of exceptions + for( i = 0 ;i < size ; i ++ ) + { + Py_INCREF( Py_None ); + PyTuple_SetItem( argsTuple.get(), i, Py_None ); + } + + // convert args to python + for( i = 0; i < size ; i ++ ) + { + PyRef val = runtime.any2PyObject( aParams[i] ); + PyTuple_SetItem( argsTuple.get(), i, val.getAcquired() ); + } + + // get callable + PyRef method(PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aFunctionName)), + SAL_NO_ACQUIRE); + raiseInvocationTargetExceptionWhenNeeded( runtime); + if( !method.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno::Adapater: Method " ).append( aFunctionName ); + buf.appendAscii( " is not implemented at object " ); + PyRef str( PyObject_Repr( mWrappedObject.get() ), SAL_NO_ACQUIRE ); + buf.appendAscii( PyString_AsString( str.get() )); + throw IllegalArgumentException( buf.makeStringAndClear(), Reference< XInterface > (),0 ); + } + + PYUNO_DEBUG_2( "entering python method %s\n" , (char*)TO_ASCII(aFunctionName) ); + PyRef pyRet( PyObject_CallObject( method.get(), argsTuple.get() ), SAL_NO_ACQUIRE ); + PYUNO_DEBUG_3( "leaving python method %s %d\n" , (char*)TO_ASCII(aFunctionName) , pyRet.is() ); + raiseInvocationTargetExceptionWhenNeeded( runtime); + if( pyRet.is() ) + { + ret = runtime.pyObject2Any( pyRet ); + + if( ret.hasValue() && + ret.getValueTypeClass() == com::sun::star::uno::TypeClass_SEQUENCE && + 0 != aFunctionName.compareToAscii( "getTypes" ) && // needed by introspection itself ! + 0 != aFunctionName.compareToAscii( "getImplementationId" ) ) // needed by introspection itself ! + { + // the sequence can either be + // 1) a simple sequence return value + // 2) a sequence, where the first element is the return value + // and the following elements are interpreted as the outparameter + // I can only decide for one solution by checking the method signature, + // so I need the reflection of the adapter ! +// if( ! mReflection.is() ) +// { +// Reference< XInterface > unoAdapter = mWeakUnoAdapter; +// if( ! unoAdapter.is() ) +// throw RuntimeException( +// OUString(RTL_CONSTASCII_USTRINGPARAM( +// "pyuno bridge: Couldn't retrieve uno adapter reference")),*this); +// mReflection = runtime.getImpl()->cargo->xCoreReflection->getType( +// makeAny( unoAdapter )); +// mWeakUnoAdapter = com::sun::star::uno::WeakReference< XInterface > (); +// } + if( ! mIntrospectionAccess.is() ) + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno bridge: Couldn't inspect uno adapter ( the python class must implement com.sun.star.lang.XTypeProvider !)" ) ), + Reference< XInterface > () ); + + { + PyThreadDetach antiguard; + Reference< XIdlMethod > method = mIntrospectionAccess->getMethod( + aFunctionName, com::sun::star::beans::MethodConcept::ALL ); + if( ! method.is( ) ) + { + throw RuntimeException( + OUStringBuffer().appendAscii("pyuno bridge: Couldn't get reflection for method " + ).append( aFunctionName ).makeStringAndClear(), + Reference< XInterface > () ); + } + + Sequence< ParamInfo > seqInfo = method->getParameterInfos(); + int i; + int nOuts = 0; + for( i = 0 ; i < seqInfo.getLength() ; i ++ ) + { + if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT || + seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT ) + { + // sequence must be interpreted as return value/outparameter tuple ! + nOuts ++; + break; + } + } + + if( nOuts ) + { + Sequence< Any > seq; + if( ! ( ret >>= seq ) ) + { + throw RuntimeException( + OUStringBuffer().appendAscii( + "pyuno bridge: Couldn't extract out parameters for method " + ).append( aFunctionName ).makeStringAndClear(), + Reference< XInterface > () ); + } + if( nOuts +1 != seq.getLength() ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno bridge: expected for method " ); + buf.append( aFunctionName ); + buf.appendAscii( " one return value and " ); + buf.append( (sal_Int32) nOuts ); + buf.appendAscii( " out parameters, got a sequence of " ); + buf.append( seq.getLength() ); + buf.appendAscii( " elements as return value." ); + throw RuntimeException(buf.makeStringAndClear(), *this ); + } + aOutParamIndex.realloc( nOuts ); + aOutParam.realloc( nOuts ); + ret = seq[0]; + sal_Int32 nOutsAssigned = 0; + for( i = 0 ; i < seqInfo.getLength() ; i ++ ) + { + if( seqInfo[i].aMode == com::sun::star::reflection::ParamMode_OUT || + seqInfo[i].aMode == com::sun::star::reflection::ParamMode_INOUT ) + { + aOutParamIndex[nOutsAssigned] = (sal_Int16) i; + aOutParam[nOutsAssigned] = seq[1+nOutsAssigned]; + nOutsAssigned ++; + } + } + } + } + // else { sequence is a return value !} + } + } + + } + PYUNO_DEBUG_1( "leaving Adapter::invoke normally\n" ); + return ret; +} + +void Adapter::setUnoAdapter( const Reference< XInterface > & unoAdapter ) +{ + // A performance nightmare. Every UNO object implemented in python needs to be introspected + // to get the knowledge about parameters. Must be solved differently + + // Even worse, the adapters do not support XWeak ! +// mWeakUnoAdapter = unoAdapter; + + Runtime runtime; + Reference< XIntrospection > xIntrospection =runtime.getImpl()->cargo->xIntrospection; + { + PyThreadDetach antiguard; + mIntrospectionAccess = xIntrospection->inspect(makeAny( unoAdapter )); + } +} + +void Adapter::setValue( const OUString & aPropertyName, const Any & value ) + throw( UnknownPropertyException, CannotConvertException, InvocationTargetException,RuntimeException) +{ + PyThreadAttach guard( mInterpreter ); + try + { + Runtime runtime; + PyRef obj = runtime.any2PyObject( value ); + + if( !hasProperty( aPropertyName ) ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName ); + buf.appendAscii( " is unknown." ); + throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + + PyObject_SetAttrString( + mWrappedObject.get(), (char*)TO_ASCII(aPropertyName), obj.get() ); + raiseInvocationTargetExceptionWhenNeeded( runtime); + + } + catch( IllegalArgumentException & exc ) + { + throw InvocationTargetException( exc.Message, *this, com::sun::star::uno::makeAny( exc ) ); + } +} + +Any Adapter::getValue( const OUString & aPropertyName ) + throw ( UnknownPropertyException, RuntimeException ) +{ + Any ret; + PyThreadAttach guard( mInterpreter ); + { + Runtime runtime; + PyRef pyRef( + PyObject_GetAttrString( mWrappedObject.get(), (char*)TO_ASCII(aPropertyName) ), + SAL_NO_ACQUIRE ); + + raiseInvocationTargetExceptionWhenNeeded( runtime); + if( !pyRef.is() ) + { + OUStringBuffer buf; + buf.appendAscii( "pyuno::Adapater: Property " ).append( aPropertyName ); + buf.appendAscii( " is unknown." ); + throw UnknownPropertyException( buf.makeStringAndClear(), Reference< XInterface > () ); + } + ret = runtime.pyObject2Any( pyRef ); + } + return ret; +} + +sal_Bool Adapter::hasMethod( const OUString & aMethodName ) + throw ( RuntimeException ) +{ + return hasProperty( aMethodName ); +} + +sal_Bool Adapter::hasProperty( const OUString & aPropertyName ) + throw ( RuntimeException ) +{ + sal_Bool bRet = sal_False; + PyThreadAttach guard( mInterpreter ); + { + bRet = PyObject_HasAttrString( + mWrappedObject.get() , (char*) TO_ASCII( aPropertyName )); + } + return bRet; +} + +} |