tdf#163486: PVS: Identical branches
[LibreOffice.git] / cppuhelper / source / component_context.cxx
blob227affa9a6197804df92949f6d6c54f8c1d1a17d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
47 #include <memory>
48 #include <utility>
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;
57 namespace cppu
60 static void try_dispose( std::unique_lock<std::mutex>& rGuard, Reference< XInterface > const & xInstance )
62 Reference< lang::XComponent > xComp( xInstance, UNO_QUERY );
63 if (xComp.is())
65 rGuard.unlock();
66 xComp->dispose();
67 rGuard.lock();
71 static void try_dispose( std::unique_lock<std::mutex>& rGuard, Reference< lang::XComponent > const & xComp )
73 if (xComp.is())
75 rGuard.unlock();
76 xComp->dispose();
77 rGuard.lock();
81 namespace {
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() );
93 public:
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 )
108 if (xSource.is())
110 xSource->addEventListener( new DisposingForwarder( xTarget ) );
114 void DisposingForwarder::disposing( lang::EventObject const & )
116 m_xTarget->dispose();
117 m_xTarget.clear();
120 namespace {
122 class ComponentContext
123 : public cppuhelper::WeakComponentImplHelper2< XComponentContext,
124 container::XNameContainer >
126 protected:
127 Reference< XComponentContext > m_xDelegate;
129 struct ContextEntry
131 Any value;
132 bool lateInit;
134 ContextEntry( Any value_, bool lateInit_ )
135 : value(std::move( value_ ))
136 , lateInit( lateInit_ )
139 typedef std::unordered_map< OUString, ContextEntry > t_map;
140 t_map m_map;
142 Reference< lang::XMultiComponentFactory > m_xSMgr;
144 protected:
145 Any lookupMap( OUString const & rName );
147 virtual void disposing(std::unique_lock<std::mutex>&) override;
148 public:
149 ComponentContext(
150 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
151 Reference< XComponentContext > const & xDelegate );
153 // XComponentContext
154 virtual Any SAL_CALL getValueByName( OUString const & rName ) override;
155 virtual Reference<lang::XMultiComponentFactory> SAL_CALL getServiceManager() override;
157 // XNameContainer
158 virtual void SAL_CALL insertByName(
159 OUString const & name, Any const & element ) override;
160 virtual void SAL_CALL removeByName( OUString const & name ) override;
161 // XNameReplace
162 virtual void SAL_CALL replaceByName(
163 OUString const & name, Any const & element ) override;
164 // XNameAccess
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;
168 // XElementAccess
169 virtual Type SAL_CALL getElementType() override;
170 virtual sal_Bool SAL_CALL hasElements() override;
175 // XNameContainer
177 void ComponentContext::insertByName(
178 OUString const & name, Any const & element )
180 ContextEntry entry(
181 element,
182 /* lateInit_: */
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(
187 name, entry ) );
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) );
204 m_map.erase(iFind);
207 // XNameReplace
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/" ) &&
219 !element.hasValue())
221 iFind->second.value.clear();
222 iFind->second.lateInit = true;
224 else
226 iFind->second.value = element;
227 iFind->second.lateInit = false;
231 // XNameAccess
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();
252 // XElementAccess
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())
272 return Any();
274 ContextEntry& rFindEntry = iFind->second;
275 if (! rFindEntry.lateInit)
276 return rFindEntry.value;
278 // late init singleton entry
279 Reference< XInterface > xInstance;
280 guard.unlock();
284 Any usesService( getValueByName( rName + "/service" ) );
285 Any args_( getValueByName( rName + "/arguments" ) );
286 Sequence<Any> args;
287 if (args_.hasValue() && !(args_ >>= args))
289 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 );
299 else
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(
319 serviceName, this );
324 catch (const RuntimeException &)
326 throw;
328 catch (const Exception & exc)
330 SAL_WARN(
331 "cppuhelper",
332 "exception occurred raising singleton \"" << rName << "\": "
333 << exc);
336 SAL_WARN_IF(!xInstance.is(),
337 "cppuhelper", "no service object raising singleton " << rName);
339 Any ret;
340 guard.lock();
341 iFind = m_map.find( rName );
342 if (iFind != m_map.end())
344 ContextEntry & rEntry = iFind->second;
345 if (rEntry.lateInit)
347 rEntry.value <<= xInstance;
348 rEntry.lateInit = false;
349 return rEntry.value;
351 ret = rEntry.value;
353 if (ret != xInstance) {
354 try_dispose( guard, xInstance );
356 return ret;
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 );
375 return ret;
378 Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
380 if ( !m_xSMgr.is() )
382 throw DeploymentException(
383 u"null component context service manager"_ustr,
384 static_cast<OWeakObject *>(this) );
386 return m_xSMgr;
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
397 if (!m_xSMgr.is() ||
398 !rName.startsWith( SMGR_SINGLETON ))
400 if (rEntry.lateInit)
402 rEntry.value.clear(); // release factory
403 rEntry.lateInit = false;
404 continue;
407 Reference< lang::XComponent > xComp;
408 rEntry.value >>= xComp;
409 if (xComp.is())
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
421 rGuard.unlock();
422 xComp->dispose();
423 rGuard.lock();
429 // dispose service manager
430 try_dispose( rGuard, m_xSMgr );
431 m_xSMgr.clear();
432 // dispose ac
433 try_dispose( rGuard, xAC );
434 // dispose tdmgr; revokes callback from cppu runtime
435 try_dispose( rGuard, xTDMgr );
437 m_map.clear();
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;
443 sal_Int32 envCount;
444 uno_getRegisteredEnvironments(
445 &envs, &envCount, &rtl_allocateMemory, u"java"_ustr.pData);
446 assert(envCount >= 0);
447 assert(envCount == 0 || envs != nullptr);
448 if (envs) {
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]);
454 std::free(envs);
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)
474 // singleton entry
475 m_map.emplace( rEntry.name, ContextEntry( Any(), true ) );
476 // service
477 m_map.emplace( rEntry.name + "/service", ContextEntry( rEntry.value, false ) );
478 // initial-arguments are provided as optional context entry
480 else
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())
488 return;
490 // wrap delegate's smgr XPropertySet into new smgr
491 Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() );
492 if (!xMgr.is())
493 return;
495 osl_atomic_increment( &m_refCount );
498 // create new smgr based on delegate's one
499 m_xSMgr.set(
500 xMgr->createInstanceWithContext(
501 u"com.sun.star.comp.stoc.OServiceManagerWrapper"_ustr, xDelegate ),
502 UNO_QUERY );
503 // patch DefaultContext property of new one
504 Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY );
505 OSL_ASSERT( xProps.is() );
506 if (xProps.is())
508 Reference< XComponentContext > xThis( this );
509 xProps->setPropertyValue( u"DefaultContext"_ustr, Any( xThis ) );
512 catch (...)
514 osl_atomic_decrement( &m_refCount );
515 throw;
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;
533 if (nEntries > 0)
537 ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate );
538 xContext.set(p);
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 );
545 xContext.clear();
548 else
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(),
575 curr2source.get());
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: */