1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <unordered_map>
22 #include <osl/diagnose.h>
23 #include <osl/mutex.hxx>
25 #include <sal/log.hxx>
27 #include <uno/lbnames.h>
28 #include <uno/mapping.hxx>
30 #include <cppuhelper/basemutex.hxx>
31 #include <cppuhelper/compbase.hxx>
32 #include <cppuhelper/component_context.hxx>
33 #include <cppuhelper/implbase.hxx>
34 #include <compbase2.hxx>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
38 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
39 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
40 #include <com/sun/star/lang/XComponent.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/uno/DeploymentException.hpp>
43 #include <com/sun/star/uno/RuntimeException.hpp>
45 #include <comphelper/sequence.hxx>
50 constexpr OUString SMGR_SINGLETON
= u
"/singletons/com.sun.star.lang.theServiceManager"_ustr
;
51 constexpr OUStringLiteral TDMGR_SINGLETON
= u
"/singletons/com.sun.star.reflection.theTypeDescriptionManager";
52 constexpr OUStringLiteral AC_SINGLETON
= u
"/singletons/com.sun.star.security.theAccessController";
54 using namespace ::com::sun::star::uno
;
55 using namespace ::com::sun::star
;
60 static void try_dispose( std::unique_lock
<std::mutex
>& rGuard
, Reference
< XInterface
> const & xInstance
)
62 Reference
< lang::XComponent
> xComp( xInstance
, UNO_QUERY
);
71 static void try_dispose( std::unique_lock
<std::mutex
>& rGuard
, Reference
< lang::XComponent
> const & xComp
)
83 class DisposingForwarder
84 : public WeakImplHelper
< lang::XEventListener
>
86 Reference
< lang::XComponent
> m_xTarget
;
88 explicit DisposingForwarder( Reference
< lang::XComponent
> const & xTarget
)
89 : m_xTarget( xTarget
)
91 OSL_ASSERT( m_xTarget
.is() );
94 // listens at source for disposing, then disposes target
95 static inline void listen(
96 Reference
< lang::XComponent
> const & xSource
,
97 Reference
< lang::XComponent
> const & xTarget
);
99 virtual void SAL_CALL
disposing( lang::EventObject
const & rSource
) override
;
104 inline void DisposingForwarder::listen(
105 Reference
< lang::XComponent
> const & xSource
,
106 Reference
< lang::XComponent
> const & xTarget
)
110 xSource
->addEventListener( new DisposingForwarder( xTarget
) );
114 void DisposingForwarder::disposing( lang::EventObject
const & )
116 m_xTarget
->dispose();
122 class ComponentContext
123 : public cppuhelper::WeakComponentImplHelper2
< XComponentContext
,
124 container::XNameContainer
>
127 Reference
< XComponentContext
> m_xDelegate
;
134 ContextEntry( Any value_
, bool lateInit_
)
135 : value(std::move( value_
))
136 , lateInit( lateInit_
)
139 typedef std::unordered_map
< OUString
, ContextEntry
> t_map
;
142 Reference
< lang::XMultiComponentFactory
> m_xSMgr
;
145 Any
lookupMap( OUString
const & rName
);
147 virtual void disposing(std::unique_lock
<std::mutex
>&) override
;
150 ContextEntry_Init
const * pEntries
, sal_Int32 nEntries
,
151 Reference
< XComponentContext
> const & xDelegate
);
154 virtual Any SAL_CALL
getValueByName( OUString
const & rName
) override
;
155 virtual Reference
<lang::XMultiComponentFactory
> SAL_CALL
getServiceManager() override
;
158 virtual void SAL_CALL
insertByName(
159 OUString
const & name
, Any
const & element
) override
;
160 virtual void SAL_CALL
removeByName( OUString
const & name
) override
;
162 virtual void SAL_CALL
replaceByName(
163 OUString
const & name
, Any
const & element
) override
;
165 virtual Any SAL_CALL
getByName( OUString
const & name
) override
;
166 virtual Sequence
<OUString
> SAL_CALL
getElementNames() override
;
167 virtual sal_Bool SAL_CALL
hasByName( OUString
const & name
) override
;
169 virtual Type SAL_CALL
getElementType() override
;
170 virtual sal_Bool SAL_CALL
hasElements() override
;
177 void ComponentContext::insertByName(
178 OUString
const & name
, Any
const & element
)
183 name
.startsWith( "/singletons/" ) &&
184 !element
.hasValue() );
185 std::unique_lock
guard( m_aMutex
);
186 std::pair
<t_map::iterator
, bool> insertion( m_map
.emplace(
188 if (! insertion
.second
)
189 throw container::ElementExistException(
190 "element already exists: " + name
,
191 static_cast<OWeakObject
*>(this) );
195 void ComponentContext::removeByName( OUString
const & name
)
197 std::unique_lock
guard( m_aMutex
);
198 t_map::iterator
iFind( m_map
.find( name
) );
199 if (iFind
== m_map
.end())
200 throw container::NoSuchElementException(
201 "no such element: " + name
,
202 static_cast<OWeakObject
*>(this) );
209 void ComponentContext::replaceByName(
210 OUString
const & name
, Any
const & element
)
212 std::unique_lock
guard( m_aMutex
);
213 t_map::iterator
iFind( m_map
.find( name
) );
214 if (iFind
== m_map
.end())
215 throw container::NoSuchElementException(
216 "no such element: " + name
,
217 static_cast<OWeakObject
*>(this) );
218 if (name
.startsWith( "/singletons/" ) &&
221 iFind
->second
.value
.clear();
222 iFind
->second
.lateInit
= true;
226 iFind
->second
.value
= element
;
227 iFind
->second
.lateInit
= false;
233 Any
ComponentContext::getByName( OUString
const & name
)
235 return getValueByName( name
);
239 Sequence
<OUString
> ComponentContext::getElementNames()
241 std::unique_lock
guard( m_aMutex
);
242 return comphelper::mapKeysToSequence(m_map
);
246 sal_Bool
ComponentContext::hasByName( OUString
const & name
)
248 std::unique_lock
guard( m_aMutex
);
249 return m_map
.find( name
) != m_map
.end();
254 Type
ComponentContext::getElementType()
256 return cppu::UnoType
<void>::get();
260 sal_Bool
ComponentContext::hasElements()
262 std::unique_lock
guard( m_aMutex
);
263 return ! m_map
.empty();
267 Any
ComponentContext::lookupMap( OUString
const & rName
)
269 std::unique_lock
guard( m_aMutex
);
270 t_map::iterator
iFind( m_map
.find( rName
) );
271 if (iFind
== m_map
.end())
274 ContextEntry
& rFindEntry
= iFind
->second
;
275 if (! rFindEntry
.lateInit
)
276 return rFindEntry
.value
;
278 // late init singleton entry
279 Reference
< XInterface
> xInstance
;
284 Any
usesService( getValueByName( rName
+ "/service" ) );
285 Any
args_( getValueByName( rName
+ "/arguments" ) );
287 if (args_
.hasValue() && !(args_
>>= args
))
292 Reference
< lang::XSingleComponentFactory
> xFac
;
293 if (usesService
>>= xFac
) // try via factory
295 xInstance
= args
.hasElements()
296 ? xFac
->createInstanceWithArgumentsAndContext( args
, this )
297 : xFac
->createInstanceWithContext( this );
301 Reference
< lang::XSingleServiceFactory
> xFac2
;
302 if (usesService
>>= xFac2
)
304 // try via old XSingleServiceFactory
305 xInstance
= args
.hasElements()
306 ? xFac2
->createInstanceWithArguments( args
)
307 : xFac2
->createInstance();
309 else if (m_xSMgr
.is()) // optionally service name
311 OUString serviceName
;
312 if ((usesService
>>= serviceName
) &&
313 !serviceName
.isEmpty())
315 xInstance
= args
.hasElements()
316 ? m_xSMgr
->createInstanceWithArgumentsAndContext(
317 serviceName
, args
, this )
318 : m_xSMgr
->createInstanceWithContext(
324 catch (const RuntimeException
&)
328 catch (const Exception
& exc
)
332 "exception occurred raising singleton \"" << rName
<< "\": "
336 SAL_WARN_IF(!xInstance
.is(),
337 "cppuhelper", "no service object raising singleton " << rName
);
341 iFind
= m_map
.find( rName
);
342 if (iFind
!= m_map
.end())
344 ContextEntry
& rEntry
= iFind
->second
;
347 rEntry
.value
<<= xInstance
;
348 rEntry
.lateInit
= false;
353 if (ret
!= xInstance
) {
354 try_dispose( guard
, xInstance
);
360 Any
ComponentContext::getValueByName( OUString
const & rName
)
362 // to determine the root context:
363 if ( rName
== "_root" )
365 if (m_xDelegate
.is())
366 return m_xDelegate
->getValueByName( rName
);
367 return Any( Reference
<XComponentContext
>(this) );
370 Any
ret( lookupMap( rName
) );
371 if (!ret
.hasValue() && m_xDelegate
.is())
373 return m_xDelegate
->getValueByName( rName
);
378 Reference
< lang::XMultiComponentFactory
> ComponentContext::getServiceManager()
382 throw DeploymentException(
383 u
"null component context service manager"_ustr
,
384 static_cast<OWeakObject
*>(this) );
389 void ComponentContext::disposing(std::unique_lock
<std::mutex
>& rGuard
)
391 Reference
< lang::XComponent
> xTDMgr
, xAC
; // to be disposed separately
393 // dispose all context objects
394 for ( auto& [rName
, rEntry
] : m_map
)
396 // service manager disposed separately
398 !rName
.startsWith( SMGR_SINGLETON
))
402 rEntry
.value
.clear(); // release factory
403 rEntry
.lateInit
= false;
407 Reference
< lang::XComponent
> xComp
;
408 rEntry
.value
>>= xComp
;
411 if ( rName
== TDMGR_SINGLETON
)
413 xTDMgr
= std::move(xComp
);
415 else if ( rName
== AC_SINGLETON
)
417 xAC
= std::move(xComp
);
419 else // dispose immediately
429 // dispose service manager
430 try_dispose( rGuard
, m_xSMgr
);
433 try_dispose( rGuard
, xAC
);
434 // dispose tdmgr; revokes callback from cppu runtime
435 try_dispose( rGuard
, xTDMgr
);
439 // Hack to terminate any JNI bridge's AsynchronousFinalizer thread (as JNI
440 // proxies get finalized with arbitrary delay, so the bridge typically does
441 // not dispose itself early enough before the process exits):
442 uno_Environment
** envs
;
444 uno_getRegisteredEnvironments(
445 &envs
, &envCount
, &rtl_allocateMemory
, u
"java"_ustr
.pData
);
446 assert(envCount
>= 0);
447 assert(envCount
== 0 || envs
!= nullptr);
449 for (sal_Int32 i
= 0; i
!= envCount
; ++i
) {
450 assert(envs
[i
] != nullptr);
451 assert(envs
[i
]->dispose
!= nullptr);
452 (*envs
[i
]->dispose
)(envs
[i
]);
458 ComponentContext::ComponentContext(
459 ContextEntry_Init
const * pEntries
, sal_Int32 nEntries
,
460 Reference
< XComponentContext
> const & xDelegate
)
461 : m_xDelegate( xDelegate
)
463 for ( sal_Int32 nPos
= 0; nPos
< nEntries
; ++nPos
)
465 ContextEntry_Init
const & rEntry
= pEntries
[ nPos
];
467 if ( rEntry
.name
== SMGR_SINGLETON
)
469 rEntry
.value
>>= m_xSMgr
;
472 if (rEntry
.bLateInitService
)
475 m_map
.emplace( rEntry
.name
, ContextEntry( Any(), true ) );
477 m_map
.emplace( rEntry
.name
+ "/service", ContextEntry( rEntry
.value
, false ) );
478 // initial-arguments are provided as optional context entry
482 // only value, no late init factory nor string
483 m_map
.emplace( rEntry
.name
, ContextEntry( rEntry
.value
, false ) );
487 if (m_xSMgr
.is() || !m_xDelegate
.is())
490 // wrap delegate's smgr XPropertySet into new smgr
491 Reference
< lang::XMultiComponentFactory
> xMgr( m_xDelegate
->getServiceManager() );
495 osl_atomic_increment( &m_refCount
);
498 // create new smgr based on delegate's one
500 xMgr
->createInstanceWithContext(
501 u
"com.sun.star.comp.stoc.OServiceManagerWrapper"_ustr
, xDelegate
),
503 // patch DefaultContext property of new one
504 Reference
< beans::XPropertySet
> xProps( m_xSMgr
, UNO_QUERY
);
505 OSL_ASSERT( xProps
.is() );
508 Reference
< XComponentContext
> xThis( this );
509 xProps
->setPropertyValue( u
"DefaultContext"_ustr
, Any( xThis
) );
514 osl_atomic_decrement( &m_refCount
);
517 osl_atomic_decrement( &m_refCount
);
518 OSL_ASSERT( m_xSMgr
.is() );
522 extern "C" { static void s_createComponentContext_v(va_list * pParam
)
524 ContextEntry_Init
const * pEntries
= va_arg(*pParam
, ContextEntry_Init
const *);
525 sal_Int32 nEntries
= va_arg(*pParam
, sal_Int32
);
526 XComponentContext
* pDelegatee
= va_arg(*pParam
, XComponentContext
*);
527 void ** ppContext
= va_arg(*pParam
, void **);
528 uno::Mapping
* pTarget2curr
= va_arg(*pParam
, uno::Mapping
*);
530 Reference
<XComponentContext
> xDelegate(pDelegatee
, SAL_NO_ACQUIRE
);
531 Reference
<XComponentContext
> xContext
;
537 ComponentContext
* p
= new ComponentContext( pEntries
, nEntries
, xDelegate
);
539 // listen delegate for disposing, to dispose this (wrapping) context first.
540 DisposingForwarder::listen( Reference
< lang::XComponent
>::query( xDelegate
), p
);
542 catch (Exception
& exc
)
544 SAL_WARN( "cppuhelper", exc
);
550 xContext
= std::move(xDelegate
);
553 *ppContext
= pTarget2curr
->mapInterface(xContext
.get(), cppu::UnoType
<decltype(xContext
)>::get());
556 Reference
< XComponentContext
> SAL_CALL
createComponentContext(
557 ContextEntry_Init
const * pEntries
, sal_Int32 nEntries
,
558 Reference
< XComponentContext
> const & xDelegate
)
560 uno::Environment
curr_env(Environment::getCurrent());
561 uno::Environment
source_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME
);
563 uno::Mapping
curr2source(curr_env
, source_env
);
564 uno::Mapping
source2curr(source_env
, curr_env
);
566 std::unique_ptr
<ContextEntry_Init
[]> mapped_entries(new ContextEntry_Init
[nEntries
]);
567 for (sal_Int32 nPos
= 0; nPos
< nEntries
; ++ nPos
)
569 mapped_entries
[nPos
].bLateInitService
= pEntries
[nPos
].bLateInitService
;
570 mapped_entries
[nPos
].name
= pEntries
[nPos
].name
;
572 uno_type_any_constructAndConvert(&mapped_entries
[nPos
].value
,
573 const_cast<void *>(pEntries
[nPos
].value
.getValue()),
574 pEntries
[nPos
].value
.getValueTypeRef(),
578 void * mapped_delegate
= curr2source
.mapInterface(xDelegate
.get(), cppu::UnoType
<decltype(xDelegate
)>::get());
579 XComponentContext
* pXComponentContext
= nullptr;
580 source_env
.invoke(s_createComponentContext_v
, mapped_entries
.get(), nEntries
, mapped_delegate
, &pXComponentContext
, &source2curr
);
581 mapped_entries
.reset();
583 return Reference
<XComponentContext
>(pXComponentContext
, SAL_NO_ACQUIRE
);
588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */