/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: proxyfac.cxx,v $ * $Revision: 1.13 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org 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 version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_stoc.hxx" #include "osl/diagnose.h" #include "osl/interlck.h" #include "osl/doublecheckedlocking.h" #include "osl/mutex.hxx" #include "rtl/ref.hxx" #include "uno/dispatcher.hxx" #include "uno/data.h" #include "uno/mapping.hxx" #include "uno/environment.hxx" #include "typelib/typedescription.hxx" #include "cppuhelper/exc_hlp.hxx" #include "cppuhelper/implbase2.hxx" #include "cppuhelper/implementationentry.hxx" #include "cppuhelper/factory.hxx" #include "com/sun/star/lang/XServiceInfo.hpp" #include "com/sun/star/registry/XRegistryKey.hpp" #include "com/sun/star/reflection/XProxyFactory.hpp" #include "com/sun/star/uno/RuntimeException.hpp" #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) #define SERVICE_NAME "com.sun.star.reflection.ProxyFactory" #define IMPL_NAME "com.sun.star.comp.reflection.ProxyFactory" using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using ::rtl::OUString; namespace { static rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT; static OUString proxyfac_getImplementationName() { return OUSTR(IMPL_NAME); } static Sequence< OUString > proxyfac_getSupportedServiceNames() { OUString str_name = OUSTR(SERVICE_NAME); return Sequence< OUString >( &str_name, 1 ); } //============================================================================== struct FactoryImpl : public ::cppu::WeakImplHelper2< lang::XServiceInfo, reflection::XProxyFactory > { Environment m_uno_env; Environment m_cpp_env; Mapping m_uno2cpp; Mapping m_cpp2uno; UnoInterfaceReference binuno_queryInterface( UnoInterfaceReference const & unoI, typelib_InterfaceTypeDescription * pTypeDescr ); FactoryImpl(); virtual ~FactoryImpl(); // XServiceInfo virtual OUString SAL_CALL getImplementationName() throw (RuntimeException); virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) throw (RuntimeException); virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw (RuntimeException); // XProxyFactory virtual Reference< XAggregation > SAL_CALL createProxy( Reference< XInterface > const & xTarget ) throw (RuntimeException); }; //______________________________________________________________________________ UnoInterfaceReference FactoryImpl::binuno_queryInterface( UnoInterfaceReference const & unoI, typelib_InterfaceTypeDescription * pTypeDescr ) { // init queryInterface() td static typelib_TypeDescription * s_pQITD = 0; if (s_pQITD == 0) { ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); if (s_pQITD == 0) { typelib_TypeDescription * pTXInterfaceDescr = 0; TYPELIB_DANGER_GET( &pTXInterfaceDescr, ::getCppuType( reinterpret_cast< Reference< XInterface > const * >(0) ).getTypeLibType() ); typelib_TypeDescription * pQITD = 0; typelib_typedescriptionreference_getDescription( &pQITD, reinterpret_cast< typelib_InterfaceTypeDescription * >( pTXInterfaceDescr )->ppAllMembers[ 0 ] ); TYPELIB_DANGER_RELEASE( pTXInterfaceDescr ); OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); s_pQITD = pQITD; } } else { OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); } void * args[ 1 ]; args[ 0 ] = &reinterpret_cast< typelib_TypeDescription * >( pTypeDescr )->pWeakRef; uno_Any ret_val, exc_space; uno_Any * exc = &exc_space; unoI.dispatch( s_pQITD, &ret_val, args, &exc ); if (exc == 0) { UnoInterfaceReference ret; if (ret_val.pType->eTypeClass == typelib_TypeClass_INTERFACE) { ret.set( *reinterpret_cast< uno_Interface ** >(ret_val.pData), SAL_NO_ACQUIRE ); typelib_typedescriptionreference_release( ret_val.pType ); } else { uno_any_destruct( &ret_val, 0 ); } return ret; } else { // exception occured: OSL_ENSURE( typelib_typedescriptionreference_isAssignableFrom( ::getCppuType( reinterpret_cast< RuntimeException const * >(0) ).getTypeLibType(), exc->pType ), "### RuntimeException expected!" ); Any cpp_exc; uno_type_copyAndConvertData( &cpp_exc, exc, ::getCppuType( &cpp_exc ).getTypeLibType(), m_uno2cpp.get() ); uno_any_destruct( exc, 0 ); ::cppu::throwException( cpp_exc ); OSL_ASSERT( 0 ); // way of no return return UnoInterfaceReference(); // for dummy } } //============================================================================== struct ProxyRoot : public ::cppu::OWeakAggObject { // XAggregation virtual Any SAL_CALL queryAggregation( Type const & rType ) throw (RuntimeException); virtual ~ProxyRoot(); inline ProxyRoot( ::rtl::Reference< FactoryImpl > const & factory, Reference< XInterface > const & xTarget ); ::rtl::Reference< FactoryImpl > m_factory; private: UnoInterfaceReference m_target; }; //============================================================================== struct binuno_Proxy : public uno_Interface { oslInterlockedCount m_nRefCount; ::rtl::Reference< ProxyRoot > m_root; UnoInterfaceReference m_target; OUString m_oid; TypeDescription m_typeDescr; inline binuno_Proxy( ::rtl::Reference< ProxyRoot > const & root, UnoInterfaceReference const & target, OUString const & oid, TypeDescription const & typeDescr ); }; extern "C" { //------------------------------------------------------------------------------ static void SAL_CALL binuno_proxy_free( uno_ExtEnvironment * pEnv, void * pProxy ) { (void) pEnv; // avoid warning about unused parameter binuno_Proxy * proxy = static_cast< binuno_Proxy * >( reinterpret_cast< uno_Interface * >( pProxy ) ); OSL_ASSERT( proxy->m_root->m_factory->m_uno_env.get()->pExtEnv == pEnv ); delete proxy; } //------------------------------------------------------------------------------ static void SAL_CALL binuno_proxy_acquire( uno_Interface * pUnoI ) { binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI ); if (osl_incrementInterlockedCount( &that->m_nRefCount ) == 1) { // rebirth of zombie uno_ExtEnvironment * uno_env = that->m_root->m_factory->m_uno_env.get()->pExtEnv; OSL_ASSERT( uno_env != 0 ); (*uno_env->registerProxyInterface)( uno_env, reinterpret_cast< void ** >( &pUnoI ), binuno_proxy_free, that->m_oid.pData, reinterpret_cast< typelib_InterfaceTypeDescription * >( that->m_typeDescr.get() ) ); OSL_ASSERT( that == static_cast< binuno_Proxy * >( pUnoI ) ); } } //------------------------------------------------------------------------------ static void SAL_CALL binuno_proxy_release( uno_Interface * pUnoI ) { binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI ); if (osl_decrementInterlockedCount( &that->m_nRefCount ) == 0) { uno_ExtEnvironment * uno_env = that->m_root->m_factory->m_uno_env.get()->pExtEnv; OSL_ASSERT( uno_env != 0 ); (*uno_env->revokeInterface)( uno_env, pUnoI ); } } //------------------------------------------------------------------------------ static void SAL_CALL binuno_proxy_dispatch( uno_Interface * pUnoI, const typelib_TypeDescription * pMemberType, void * pReturn, void * pArgs [], uno_Any ** ppException ) { binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI ); switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription const * >( pMemberType )->nPosition) { case 0: // queryInterface() { try { Type const & rType = *reinterpret_cast< Type const * >( pArgs[ 0 ] ); Any ret( that->m_root->queryInterface( rType ) ); uno_type_copyAndConvertData( pReturn, &ret, ::getCppuType( &ret ).getTypeLibType(), that->m_root->m_factory->m_cpp2uno.get() ); *ppException = 0; // no exc } catch (RuntimeException &) { Any exc( ::cppu::getCaughtException() ); uno_type_any_constructAndConvert( *ppException, const_cast< void * >(exc.getValue()), exc.getValueTypeRef(), that->m_root->m_factory->m_cpp2uno.get() ); } break; } case 1: // acquire() binuno_proxy_acquire( pUnoI ); *ppException = 0; // no exc break; case 2: // release() binuno_proxy_release( pUnoI ); *ppException = 0; // no exc break; default: that->m_target.dispatch( pMemberType, pReturn, pArgs, ppException ); break; } } } //______________________________________________________________________________ inline binuno_Proxy::binuno_Proxy( ::rtl::Reference< ProxyRoot > const & root, UnoInterfaceReference const & target, OUString const & oid, TypeDescription const & typeDescr ) : m_nRefCount( 1 ), m_root( root ), m_target( target ), m_oid( oid ), m_typeDescr( typeDescr ) { uno_Interface::acquire = binuno_proxy_acquire; uno_Interface::release = binuno_proxy_release; uno_Interface::pDispatcher = binuno_proxy_dispatch; } //______________________________________________________________________________ ProxyRoot::~ProxyRoot() { } //______________________________________________________________________________ inline ProxyRoot::ProxyRoot( ::rtl::Reference< FactoryImpl > const & factory, Reference< XInterface > const & xTarget ) : m_factory( factory ) { m_factory->m_cpp2uno.mapInterface( reinterpret_cast< void ** >( &m_target.m_pUnoI ), xTarget.get(), ::getCppuType( &xTarget ) ); OSL_ENSURE( m_target.is(), "### mapping interface failed!" ); } //______________________________________________________________________________ Any ProxyRoot::queryAggregation( Type const & rType ) throw (RuntimeException) { Any ret( OWeakAggObject::queryAggregation( rType ) ); if (! ret.hasValue()) { typelib_TypeDescription * pTypeDescr = 0; TYPELIB_DANGER_GET( &pTypeDescr, rType.getTypeLibType() ); try { Reference< XInterface > xProxy; uno_ExtEnvironment * cpp_env = m_factory->m_cpp_env.get()->pExtEnv; OSL_ASSERT( cpp_env != 0 ); // mind a new delegator, calculate current root: Reference< XInterface > xRoot( static_cast< OWeakObject * >(this), UNO_QUERY_THROW ); OUString oid; (*cpp_env->getObjectIdentifier)( cpp_env, &oid.pData, xRoot.get() ); OSL_ASSERT( oid.getLength() > 0 ); (*cpp_env->getRegisteredInterface)( cpp_env, reinterpret_cast< void ** >( &xProxy ), oid.pData, reinterpret_cast< typelib_InterfaceTypeDescription * >(pTypeDescr) ); if (! xProxy.is()) { // perform query on target: UnoInterfaceReference proxy_target( m_factory->binuno_queryInterface( m_target, reinterpret_cast< typelib_InterfaceTypeDescription * >(pTypeDescr) ) ); if (proxy_target.is()) { // ensure root's object entries: UnoInterfaceReference root; m_factory->m_cpp2uno.mapInterface( reinterpret_cast< void ** >( &root.m_pUnoI ), xRoot.get(), ::getCppuType( &xRoot ) ); UnoInterfaceReference proxy( // ref count initially 1: new binuno_Proxy( this, proxy_target, oid, pTypeDescr ), SAL_NO_ACQUIRE ); uno_ExtEnvironment * uno_env = m_factory->m_uno_env.get()->pExtEnv; OSL_ASSERT( uno_env != 0 ); (*uno_env->registerProxyInterface)( uno_env, reinterpret_cast< void ** >( &proxy.m_pUnoI ), binuno_proxy_free, oid.pData, reinterpret_cast< typelib_InterfaceTypeDescription * >( pTypeDescr ) ); m_factory->m_uno2cpp.mapInterface( reinterpret_cast< void ** >( &xProxy ), proxy.get(), pTypeDescr ); } } if (xProxy.is()) ret.setValue( &xProxy, pTypeDescr ); } catch (...) // finally { TYPELIB_DANGER_RELEASE( pTypeDescr ); throw; } TYPELIB_DANGER_RELEASE( pTypeDescr ); } return ret; } //############################################################################## //______________________________________________________________________________ FactoryImpl::FactoryImpl() { OUString uno = OUSTR(UNO_LB_UNO); OUString cpp = OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME); uno_getEnvironment( reinterpret_cast< uno_Environment ** >( &m_uno_env ), uno.pData, 0 ); OSL_ENSURE( m_uno_env.is(), "### cannot get binary uno env!" ); uno_getEnvironment( reinterpret_cast< uno_Environment ** >( &m_cpp_env ), cpp.pData, 0 ); OSL_ENSURE( m_cpp_env.is(), "### cannot get C++ uno env!" ); uno_getMapping( reinterpret_cast< uno_Mapping ** >( &m_uno2cpp ), m_uno_env.get(), m_cpp_env.get(), 0 ); OSL_ENSURE( m_uno2cpp.is(), "### cannot get bridge uno <-> C++!" ); uno_getMapping( reinterpret_cast< uno_Mapping ** >( &m_cpp2uno ), m_cpp_env.get(), m_uno_env.get(), 0 ); OSL_ENSURE( m_cpp2uno.is(), "### cannot get bridge C++ <-> uno!" ); g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt ); } //______________________________________________________________________________ FactoryImpl::~FactoryImpl() { g_moduleCount.modCnt.release( &g_moduleCount.modCnt ); } // XProxyFactory //______________________________________________________________________________ Reference< XAggregation > FactoryImpl::createProxy( Reference< XInterface > const & xTarget ) throw (RuntimeException) { return new ProxyRoot( this, xTarget ); } // XServiceInfo //______________________________________________________________________________ OUString FactoryImpl::getImplementationName() throw (RuntimeException) { return proxyfac_getImplementationName();; } //______________________________________________________________________________ sal_Bool FactoryImpl::supportsService( const OUString & rServiceName ) throw (RuntimeException) { Sequence< OUString > const & rSNL = getSupportedServiceNames(); OUString const * pArray = rSNL.getConstArray(); for ( sal_Int32 nPos = rSNL.getLength(); nPos--; ) { if (rServiceName.equals( pArray[ nPos ] )) return true; } return false; } //______________________________________________________________________________ Sequence< OUString > FactoryImpl::getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException) { return proxyfac_getSupportedServiceNames(); } //============================================================================== static Reference< XInterface > SAL_CALL proxyfac_create( Reference< XComponentContext > const & ) throw (Exception) { Reference< XInterface > xRet; { ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() ); static WeakReference < XInterface > rwInstance; xRet = rwInstance; if (! xRet.is()) { xRet = static_cast< ::cppu::OWeakObject * >(new FactoryImpl); rwInstance = xRet; } } return xRet; } static ::cppu::ImplementationEntry g_entries [] = { { proxyfac_create, proxyfac_getImplementationName, proxyfac_getSupportedServiceNames, ::cppu::createSingleComponentFactory, &g_moduleCount.modCnt, 0 }, { 0, 0, 0, 0, 0, 0 } }; } extern "C" { sal_Bool SAL_CALL component_canUnload( TimeValue * pTime ) { return g_moduleCount.canUnload( &g_moduleCount, pTime ); } void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** ) { *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; } sal_Bool SAL_CALL component_writeInfo( void * pServiceManager, void * pRegistryKey ) { return ::cppu::component_writeInfoHelper( pServiceManager, pRegistryKey, g_entries ); } void * SAL_CALL component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) { return ::cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey, g_entries ); } }