diff options
Diffstat (limited to 'cppuhelper/source/component_context.cxx')
-rw-r--r-- | cppuhelper/source/component_context.cxx | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/cppuhelper/source/component_context.cxx b/cppuhelper/source/component_context.cxx new file mode 100644 index 000000000000..306490aa1616 --- /dev/null +++ b/cppuhelper/source/component_context.cxx @@ -0,0 +1,902 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + /************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppuhelper.hxx" + +#ifdef DIAG +#define CONTEXT_DIAG +#endif + +#if OSL_DEBUG_LEVEL > 0 +#include <stdio.h> +#endif + +#include <vector> +#include <hash_map> +#ifdef CONTEXT_DIAG +#include <map> +#endif + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> + +#include <rtl/ustrbuf.hxx> + +#include <uno/mapping.hxx> + +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/compbase2.hxx> +#include <cppuhelper/component_context.hxx> +#include <cppuhelper/exc_hlp.hxx> + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include "com/sun/star/uno/RuntimeException.hpp" + +#include <hash_map> +#include <memory> + +#define SMGR_SINGLETON "/singletons/com.sun.star.lang.theServiceManager" +#define TDMGR_SINGLETON "/singletons/com.sun.star.reflection.theTypeDescriptionManager" +#define AC_SINGLETON "/singletons/com.sun.star.security.theAccessController" +#define AC_POLICY "/singletons/com.sun.star.security.thePolicy" +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + + +using namespace ::osl; +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +namespace cppu +{ + +#ifdef CONTEXT_DIAG +//-------------------------------------------------------------------------------------------------- +static OUString val2str( void const * pVal, typelib_TypeDescriptionReference * pTypeRef ) +{ + OSL_ASSERT( pVal ); + if (pTypeRef->eTypeClass == typelib_TypeClass_VOID) + return OUSTR("void"); + + OUStringBuffer buf( 64 ); + buf.append( (sal_Unicode)'(' ); + buf.append( pTypeRef->pTypeName ); + buf.append( (sal_Unicode)')' ); + + switch (pTypeRef->eTypeClass) + { + case typelib_TypeClass_INTERFACE: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int64)*(void **)pVal, 16 ); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + typelib_TypeDescription * pTypeDescr = 0; + ::typelib_typedescriptionreference_getDescription( &pTypeDescr, pTypeRef ); + OSL_ASSERT( pTypeDescr ); + if (! pTypeDescr->bComplete) + ::typelib_typedescription_complete( &pTypeDescr ); + + typelib_CompoundTypeDescription * pCompType = (typelib_CompoundTypeDescription *)pTypeDescr; + sal_Int32 nDescr = pCompType->nMembers; + + if (pCompType->pBaseTypeDescription) + { + buf.append( val2str( pVal, ((typelib_TypeDescription *)pCompType->pBaseTypeDescription)->pWeakRef ) ); + if (nDescr) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + + typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs; + sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets; + rtl_uString ** ppMemberNames = pCompType->ppMemberNames; + + for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos ) + { + buf.append( ppMemberNames[ nPos ] ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" = ") ); + typelib_TypeDescription * pMemberType = 0; + TYPELIB_DANGER_GET( &pMemberType, ppTypeRefs[ nPos ] ); + buf.append( val2str( (char *)pVal + pMemberOffsets[ nPos ], pMemberType->pWeakRef ) ); + TYPELIB_DANGER_RELEASE( pMemberType ); + if (nPos < (nDescr -1)) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + + ::typelib_typedescription_release( pTypeDescr ); + + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + break; + } + case typelib_TypeClass_SEQUENCE: + { + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); + + uno_Sequence * pSequence = *(uno_Sequence **)pVal; + typelib_TypeDescription * pElementTypeDescr = 0; + TYPELIB_DANGER_GET( &pElementTypeDescr, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType ); + + sal_Int32 nElementSize = pElementTypeDescr->nSize; + sal_Int32 nElements = pSequence->nElements; + + if (nElements) + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + char * pElements = pSequence->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + buf.append( val2str( pElements + (nElementSize * nPos), pElementTypeDescr->pWeakRef ) ); + if (nPos < (nElements -1)) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + } + else + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{}") ); + } + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + break; + } + case typelib_TypeClass_ANY: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") ); + buf.append( val2str( ((uno_Any *)pVal)->pData, + ((uno_Any *)pVal)->pType ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") ); + break; + case typelib_TypeClass_TYPE: + buf.append( (*(typelib_TypeDescriptionReference **)pVal)->pTypeName ); + break; + case typelib_TypeClass_STRING: + buf.append( (sal_Unicode)'\"' ); + buf.append( *(rtl_uString **)pVal ); + buf.append( (sal_Unicode)'\"' ); + break; + case typelib_TypeClass_ENUM: + { + typelib_TypeDescription * pTypeDescr = 0; + ::typelib_typedescriptionreference_getDescription( &pTypeDescr, pTypeRef ); + OSL_ASSERT( pTypeDescr ); + if (! pTypeDescr->bComplete) + ::typelib_typedescription_complete( &pTypeDescr ); + + sal_Int32 * pValues = ((typelib_EnumTypeDescription *)pTypeDescr)->pEnumValues; + sal_Int32 nPos = ((typelib_EnumTypeDescription *)pTypeDescr)->nEnumValues; + while (nPos--) + { + if (pValues[ nPos ] == *(sal_Int32 *)pVal) + break; + } + if (nPos >= 0) + buf.append( ((typelib_EnumTypeDescription *)pTypeDescr)->ppEnumNames[ nPos ] ); + else + buf.append( (sal_Unicode)'?' ); + + ::typelib_typedescription_release( pTypeDescr ); + break; + } + case typelib_TypeClass_BOOLEAN: + if (*(sal_Bool *)pVal) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("true") ); + else + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("false") ); + break; + case typelib_TypeClass_CHAR: + buf.append( (sal_Unicode)'\'' ); + buf.append( *(sal_Unicode *)pVal ); + buf.append( (sal_Unicode)'\'' ); + break; + case typelib_TypeClass_FLOAT: + buf.append( *(float *)pVal ); + break; + case typelib_TypeClass_DOUBLE: + buf.append( *(double *)pVal ); + break; + case typelib_TypeClass_BYTE: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int32)*(sal_Int8 *)pVal, 16 ); + break; + case typelib_TypeClass_SHORT: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int32)*(sal_Int16 *)pVal, 16 ); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int32)*(sal_uInt16 *)pVal, 16 ); + break; + case typelib_TypeClass_LONG: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( *(sal_Int32 *)pVal, 16 ); + break; + case typelib_TypeClass_UNSIGNED_LONG: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); + buf.append( (sal_Int64)*(sal_uInt32 *)pVal, 16 ); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") ); +#if defined(GCC) && defined(SPARC) + { + sal_Int64 aVal; + *(sal_Int32 *)&aVal = *(sal_Int32 *)pVal; + *((sal_Int32 *)&aVal +1)= *((sal_Int32 *)pVal +1); + buf.append( aVal, 16 ); + } +#else + buf.append( *(sal_Int64 *)pVal, 16 ); +#endif + break; + default: + buf.append( (sal_Unicode)'?' ); + } + + return buf.makeStringAndClear(); +} +//-------------------------------------------------------------------------------------------------- +static void dumpEntry( OUString const & key, Any const & value ) +{ + OUString val( val2str( value.getValue(), value.getValueTypeRef() ) ); + OString key_str( OUStringToOString( key, RTL_TEXTENCODING_ASCII_US ) ); + OString val_str( OUStringToOString( val, RTL_TEXTENCODING_ASCII_US ) ); + ::fprintf( stderr, "| %s = %s\n", key_str.getStr(), val_str.getStr() ); +} +#endif +//-------------------------------------------------------------------------------------------------- +static inline void try_dispose( Reference< XInterface > const & xInstance ) + SAL_THROW( (RuntimeException) ) +{ + Reference< lang::XComponent > xComp( xInstance, UNO_QUERY ); + if (xComp.is()) + { + xComp->dispose(); + } +} +//-------------------------------------------------------------------------------------------------- +static inline void try_dispose( Reference< lang::XComponent > const & xComp ) + SAL_THROW( (RuntimeException) ) +{ + if (xComp.is()) + { + xComp->dispose(); + } +} + +//================================================================================================== + +class DisposingForwarder + : public WeakImplHelper1< lang::XEventListener > +{ + Reference< lang::XComponent > m_xTarget; + + inline DisposingForwarder( Reference< lang::XComponent > const & xTarget ) + SAL_THROW( () ) + : m_xTarget( xTarget ) + { OSL_ASSERT( m_xTarget.is() ); } +public: + // listens at source for disposing, then disposes target + static inline void listen( + Reference< lang::XComponent > const & xSource, + Reference< lang::XComponent > const & xTarget ) + SAL_THROW( (RuntimeException) ); + + virtual void SAL_CALL disposing( lang::EventObject const & rSource ) + throw (RuntimeException); +}; +//__________________________________________________________________________________________________ +inline void DisposingForwarder::listen( + Reference< lang::XComponent > const & xSource, + Reference< lang::XComponent > const & xTarget ) + SAL_THROW( (RuntimeException) ) +{ + if (xSource.is()) + { + xSource->addEventListener( new DisposingForwarder( xTarget ) ); + } +} +//__________________________________________________________________________________________________ +void DisposingForwarder::disposing( lang::EventObject const & ) + throw (RuntimeException) +{ + m_xTarget->dispose(); + m_xTarget.clear(); +} + +//================================================================================================== +struct MutexHolder +{ +protected: + Mutex m_mutex; +}; +//================================================================================================== + +class ComponentContext + : private MutexHolder + , public WeakComponentImplHelper2< XComponentContext, + container::XNameContainer > +{ +protected: + Reference< XComponentContext > m_xDelegate; + + struct ContextEntry + { + Any value; + bool lateInit; + + inline ContextEntry( Any const & value_, bool lateInit_ ) + : value( value_ ) + , lateInit( lateInit_ ) + {} + }; + typedef ::std::hash_map< OUString, ContextEntry * , OUStringHash > t_map; + t_map m_map; + + Reference< lang::XMultiComponentFactory > m_xSMgr; + +protected: + Any lookupMap( OUString const & rName ) + SAL_THROW( (RuntimeException) ); + + virtual void SAL_CALL disposing(); +public: + ComponentContext( + ContextEntry_Init const * pEntries, sal_Int32 nEntries, + Reference< XComponentContext > const & xDelegate ); + virtual ~ComponentContext() + SAL_THROW( () ); + + // XComponentContext + virtual Any SAL_CALL getValueByName( OUString const & rName ) + throw (RuntimeException); + virtual Reference<lang::XMultiComponentFactory> SAL_CALL getServiceManager() + throw (RuntimeException); + + // XNameContainer + virtual void SAL_CALL insertByName( + OUString const & name, Any const & element ) + throw (lang::IllegalArgumentException, container::ElementExistException, + lang::WrappedTargetException, RuntimeException); + virtual void SAL_CALL removeByName( OUString const & name ) + throw (container::NoSuchElementException, + lang::WrappedTargetException, RuntimeException); + // XNameReplace + virtual void SAL_CALL replaceByName( + OUString const & name, Any const & element ) + throw (lang::IllegalArgumentException,container::NoSuchElementException, + lang::WrappedTargetException, RuntimeException); + // XNameAccess + virtual Any SAL_CALL getByName( OUString const & name ) + throw (container::NoSuchElementException, + lang::WrappedTargetException, RuntimeException); + virtual Sequence<OUString> SAL_CALL getElementNames() + throw (RuntimeException); + virtual sal_Bool SAL_CALL hasByName( OUString const & name ) + throw (RuntimeException); + // XElementAccess + virtual Type SAL_CALL getElementType() throw (RuntimeException); + virtual sal_Bool SAL_CALL hasElements() throw (RuntimeException); +}; + +// XNameContainer +//______________________________________________________________________________ +void ComponentContext::insertByName( + OUString const & name, Any const & element ) + throw (lang::IllegalArgumentException, container::ElementExistException, + lang::WrappedTargetException, RuntimeException) +{ + t_map::mapped_type entry( + new ContextEntry( + element, + /* lateInit_: */ + name.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("/singletons/") ) && + !element.hasValue() ) ); + MutexGuard guard( m_mutex ); + ::std::pair<t_map::iterator, bool> insertion( m_map.insert( + t_map::value_type( name, entry ) ) ); + if (! insertion.second) + throw container::ElementExistException( + OUSTR("element already exists: ") + name, + static_cast<OWeakObject *>(this) ); +} + +//______________________________________________________________________________ +void ComponentContext::removeByName( OUString const & name ) + throw (container::NoSuchElementException, + lang::WrappedTargetException, RuntimeException) +{ + MutexGuard guard( m_mutex ); + t_map::iterator iFind( m_map.find( name ) ); + if (iFind == m_map.end()) + throw container::NoSuchElementException( + OUSTR("no such element: ") + name, + static_cast<OWeakObject *>(this) ); + + delete iFind->second; + m_map.erase(iFind); +} + +// XNameReplace +//______________________________________________________________________________ +void ComponentContext::replaceByName( + OUString const & name, Any const & element ) + throw (lang::IllegalArgumentException,container::NoSuchElementException, + lang::WrappedTargetException, RuntimeException) +{ + MutexGuard guard( m_mutex ); + t_map::const_iterator const iFind( m_map.find( name ) ); + if (iFind == m_map.end()) + throw container::NoSuchElementException( + OUSTR("no such element: ") + name, + static_cast<OWeakObject *>(this) ); + if (name.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("/singletons/") ) && + !element.hasValue()) + { + iFind->second->value.clear(); + iFind->second->lateInit = true; + } + else + { + iFind->second->value = element; + iFind->second->lateInit = false; + } +} + +// XNameAccess +//______________________________________________________________________________ +Any ComponentContext::getByName( OUString const & name ) + throw (container::NoSuchElementException, + lang::WrappedTargetException, RuntimeException) +{ + return getValueByName( name ); +} + +//______________________________________________________________________________ +Sequence<OUString> ComponentContext::getElementNames() + throw (RuntimeException) +{ + MutexGuard guard( m_mutex ); + Sequence<OUString> ret( m_map.size() ); + OUString * pret = ret.getArray(); + sal_Int32 pos = 0; + t_map::const_iterator iPos( m_map.begin() ); + t_map::const_iterator const iEnd( m_map.end() ); + for ( ; iPos != iEnd; ++iPos ) + pret[pos++] = iPos->first; + return ret; +} + +//______________________________________________________________________________ +sal_Bool ComponentContext::hasByName( OUString const & name ) + throw (RuntimeException) +{ + MutexGuard guard( m_mutex ); + return m_map.find( name ) != m_map.end(); +} + +// XElementAccess +//______________________________________________________________________________ +Type ComponentContext::getElementType() throw (RuntimeException) +{ + return ::getVoidCppuType(); +} + +//______________________________________________________________________________ +sal_Bool ComponentContext::hasElements() throw (RuntimeException) +{ + MutexGuard guard( m_mutex ); + return ! m_map.empty(); +} + +//__________________________________________________________________________________________________ +Any ComponentContext::lookupMap( OUString const & rName ) + SAL_THROW( (RuntimeException) ) +{ +#ifdef CONTEXT_DIAG + if (rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("dump_maps") )) + { + ::fprintf( stderr, ">>> dumping out ComponentContext %p m_map:\n", this ); + typedef ::std::map< OUString, ContextEntry * > t_sorted; // sorted map + t_sorted sorted; + for ( t_map::const_iterator iPos( m_map.begin() ); iPos != m_map.end(); ++iPos ) + { + sorted[ iPos->first ] = iPos->second; + } + { + for ( t_sorted::const_iterator iPos( sorted.begin() ); iPos != sorted.end(); ++iPos ) + { + dumpEntry( iPos->first, iPos->second->value ); + } + } + return Any(); + } +#endif + + ResettableMutexGuard guard( m_mutex ); + t_map::const_iterator iFind( m_map.find( rName ) ); + if (iFind == m_map.end()) + return Any(); + + t_map::mapped_type pEntry = iFind->second; + if (! pEntry->lateInit) + return pEntry->value; + + // late init singleton entry + Reference< XInterface > xInstance; + guard.clear(); + + try + { + Any usesService( getValueByName( rName + OUSTR("/service") ) ); + Any args_( getValueByName( rName + OUSTR("/arguments") ) ); + Sequence<Any> args; + if (args_.hasValue() && !(args_ >>= args)) + { + args.realloc( 1 ); + args[ 0 ] = args_; + } + + Reference< lang::XSingleComponentFactory > xFac; + if (usesService >>= xFac) // try via factory + { + xInstance = args.getLength() + ? xFac->createInstanceWithArgumentsAndContext( args, this ) + : xFac->createInstanceWithContext( this ); + } + else + { + Reference< lang::XSingleServiceFactory > xFac2; + if (usesService >>= xFac2) + { + // try via old XSingleServiceFactory +#if OSL_DEBUG_LEVEL > 0 + ::fprintf( + stderr, + "### omitting context for service instanciation!\n" ); +#endif + xInstance = args.getLength() + ? xFac2->createInstanceWithArguments( args ) + : xFac2->createInstance(); + } + else if (m_xSMgr.is()) // optionally service name + { + OUString serviceName; + if ((usesService >>= serviceName) && + serviceName.getLength()) + { + xInstance = args.getLength() + ? m_xSMgr->createInstanceWithArgumentsAndContext( + serviceName, args, this ) + : m_xSMgr->createInstanceWithContext( + serviceName, this ); + } + } + } + } + catch (RuntimeException &) + { + throw; + } + catch (Exception & exc) // rethrow as WrappedTargetRuntimeException + { + Any caught( getCaughtException() ); + OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "exception occured raising singleton \"") ); + buf.append( rName ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\": ") ); + buf.append( exc.Message ); + throw lang::WrappedTargetRuntimeException( + buf.makeStringAndClear(), static_cast<OWeakObject *>(this),caught ); + } + + if (! xInstance.is()) + { + throw RuntimeException( + OUSTR("no service object raising singleton ") + rName, + static_cast<OWeakObject *>(this) ); + } + + Any ret; + guard.reset(); + iFind = m_map.find( rName ); + if (iFind != m_map.end()) + { + pEntry = iFind->second; + if (pEntry->lateInit) + { + pEntry->value <<= xInstance; + pEntry->lateInit = false; + return pEntry->value; + } + else + ret = pEntry->value; + } + guard.clear(); + try_dispose( xInstance ); + return ret; +} + +//__________________________________________________________________________________________________ +Any ComponentContext::getValueByName( OUString const & rName ) + throw (RuntimeException) +{ + // to determine the root context: + if (rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("_root") )) + { + if (m_xDelegate.is()) + return m_xDelegate->getValueByName( rName ); + else + return makeAny( Reference<XComponentContext>(this) ); + } + + Any ret( lookupMap( rName ) ); + if (!ret.hasValue() && m_xDelegate.is()) + { + return m_xDelegate->getValueByName( rName ); + } + return ret; +} +//__________________________________________________________________________________________________ +Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager() + throw (RuntimeException) +{ + return m_xSMgr; +} +//__________________________________________________________________________________________________ +ComponentContext::~ComponentContext() + SAL_THROW( () ) +{ +#ifdef CONTEXT_DIAG + ::fprintf( stderr, "> destructed context %p\n", this ); +#endif + t_map::const_iterator iPos( m_map.begin() ); + t_map::const_iterator const iEnd( m_map.end() ); + for ( ; iPos != iEnd; ++iPos ) + delete iPos->second; + m_map.clear(); +} +//__________________________________________________________________________________________________ +void ComponentContext::disposing() +{ +#ifdef CONTEXT_DIAG + ::fprintf( stderr, "> disposing context %p\n", this ); +#endif + + Reference< lang::XComponent > xTDMgr, xAC, xPolicy; // to be disposed separately + + // dispose all context objects + t_map::const_iterator iPos( m_map.begin() ); + t_map::const_iterator const iEnd( m_map.end() ); + for ( ; iPos != iEnd; ++iPos ) + { + t_map::mapped_type pEntry = iPos->second; + + // service manager disposed separately + if (!m_xSMgr.is() || + !iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_SINGLETON) )) + { + if (pEntry->lateInit) + { + // late init + MutexGuard guard( m_mutex ); + if (pEntry->lateInit) + { + pEntry->value.clear(); // release factory + pEntry->lateInit = false; + continue; + } + } + + Reference< lang::XComponent > xComp; + pEntry->value >>= xComp; + if (xComp.is()) + { + if (iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(TDMGR_SINGLETON) )) + { + xTDMgr = xComp; + } + else if (iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(AC_SINGLETON) )) + { + xAC = xComp; + } + else if (iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(AC_POLICY) )) + { + xPolicy = xComp; + } + else // dispose immediately + { + xComp->dispose(); + } + } + } + } + + // dispose service manager + try_dispose( m_xSMgr ); + m_xSMgr.clear(); + // dispose ac + try_dispose( xAC ); + // dispose policy + try_dispose( xPolicy ); + // dispose tdmgr; revokes callback from cppu runtime + try_dispose( xTDMgr ); + + iPos = m_map.begin(); + for ( ; iPos != iEnd; ++iPos ) + delete iPos->second; + m_map.clear(); +} +//__________________________________________________________________________________________________ +ComponentContext::ComponentContext( + ContextEntry_Init const * pEntries, sal_Int32 nEntries, + Reference< XComponentContext > const & xDelegate ) + : WeakComponentImplHelper2< XComponentContext, container::XNameContainer >( + m_mutex ), + m_xDelegate( xDelegate ) +{ + for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos ) + { + ContextEntry_Init const & rEntry = pEntries[ nPos ]; + + if (rEntry.name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_SINGLETON) )) + { + rEntry.value >>= m_xSMgr; + } + + if (rEntry.bLateInitService) + { + // singleton entry + m_map[ rEntry.name ] = new ContextEntry( Any(), true ); + // /service + m_map[ rEntry.name + OUSTR("/service") ] = new ContextEntry( rEntry.value, false ); + // /initial-arguments are provided as optional context entry + } + else + { + // only value, no late init factory nor string + m_map[ rEntry.name ] = new ContextEntry( rEntry.value, false ); + } + } + + if (!m_xSMgr.is() && m_xDelegate.is()) + { + // wrap delegate's smgr XPropertySet into new smgr + Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() ); + if (xMgr.is()) + { + osl_incrementInterlockedCount( &m_refCount ); + try + { + // create new smgr based on delegate's one + m_xSMgr.set( + xMgr->createInstanceWithContext( + OUSTR("com.sun.star.comp.stoc.OServiceManagerWrapper"), xDelegate ), + UNO_QUERY ); + // patch DefaultContext property of new one + Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY ); + OSL_ASSERT( xProps.is() ); + if (xProps.is()) + { + Reference< XComponentContext > xThis( this ); + xProps->setPropertyValue( OUSTR("DefaultContext"), makeAny( xThis ) ); + } + } + catch (...) + { + osl_decrementInterlockedCount( &m_refCount ); + throw; + } + osl_decrementInterlockedCount( &m_refCount ); + OSL_ASSERT( m_xSMgr.is() ); + } + } +} + + +//################################################################################################## +extern "C" { static void s_createComponentContext_v(va_list * pParam) +{ + ContextEntry_Init const * pEntries = va_arg(*pParam, ContextEntry_Init const *); + sal_Int32 nEntries = va_arg(*pParam, sal_Int32); + XComponentContext * pDelegatee = va_arg(*pParam, XComponentContext *); + void ** ppContext = va_arg(*pParam, void **); + uno::Mapping * pTarget2curr = va_arg(*pParam, uno::Mapping *); + + Reference<XComponentContext> xDelegate(pDelegatee, SAL_NO_ACQUIRE); + Reference<XComponentContext> xContext; + + if (nEntries > 0) + { + try + { + ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate ); + xContext.set(p); + // listen delegate for disposing, to dispose this (wrapping) context first. + DisposingForwarder::listen( Reference< lang::XComponent >::query( xDelegate ), p ); + } + catch (Exception & exc) + { + (void) exc; // avoid warning about unused variable + OSL_ENSURE( 0, OUStringToOString( + exc.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); + xContext.clear(); + } + } + else + { + xContext = xDelegate; + } + + delete[] pEntries; + + *ppContext = pTarget2curr->mapInterface(xContext.get(), ::getCppuType(&xContext)); +}} + +Reference< XComponentContext > SAL_CALL createComponentContext( + ContextEntry_Init const * pEntries, sal_Int32 nEntries, + Reference< XComponentContext > const & xDelegate ) + SAL_THROW( () ) +{ + uno::Environment curr_env(Environment::getCurrent()); + uno::Environment source_env(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(CPPU_STRINGIFY(CPPU_ENV)))); + + uno::Mapping curr2source(curr_env, source_env); + uno::Mapping source2curr(source_env, curr_env); + + ContextEntry_Init * mapped_entries = new ContextEntry_Init[nEntries]; + for (sal_Int32 nPos = 0; nPos < nEntries; ++ nPos) + { + mapped_entries[nPos].bLateInitService = pEntries[nPos].bLateInitService; + mapped_entries[nPos].name = pEntries[nPos].name; + + uno_type_any_constructAndConvert(&mapped_entries[nPos].value, + const_cast<void *>(pEntries[nPos].value.getValue()), + pEntries[nPos].value.getValueTypeRef(), + curr2source.get()); + } + + void * mapped_delegate = curr2source.mapInterface(xDelegate.get(), ::getCppuType(&xDelegate)); + XComponentContext * pXComponentContext = NULL; + source_env.invoke(s_createComponentContext_v, mapped_entries, nEntries, mapped_delegate, &pXComponentContext, &source2curr); + + return Reference<XComponentContext>(pXComponentContext, SAL_NO_ACQUIRE); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |