android: Update app-specific/MIME type icons
[LibreOffice.git] / cppuhelper / source / component_context.cxx
blob21604a6bcd1bc271379579b8262c22f38bfecbc3
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 OUStringLiteral SMGR_SINGLETON = u"/singletons/com.sun.star.lang.theServiceManager";
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 ::osl;
55 using namespace ::com::sun::star::uno;
56 using namespace ::com::sun::star;
58 namespace cppu
61 static void try_dispose( std::unique_lock<std::mutex>& rGuard, Reference< XInterface > const & xInstance )
63 Reference< lang::XComponent > xComp( xInstance, UNO_QUERY );
64 if (xComp.is())
66 rGuard.unlock();
67 xComp->dispose();
68 rGuard.lock();
72 static void try_dispose( std::unique_lock<std::mutex>& rGuard, Reference< lang::XComponent > const & xComp )
74 if (xComp.is())
76 rGuard.unlock();
77 xComp->dispose();
78 rGuard.lock();
82 namespace {
84 class DisposingForwarder
85 : public WeakImplHelper< lang::XEventListener >
87 Reference< lang::XComponent > m_xTarget;
89 explicit DisposingForwarder( Reference< lang::XComponent > const & xTarget )
90 : m_xTarget( xTarget )
92 OSL_ASSERT( m_xTarget.is() );
94 public:
95 // listens at source for disposing, then disposes target
96 static inline void listen(
97 Reference< lang::XComponent > const & xSource,
98 Reference< lang::XComponent > const & xTarget );
100 virtual void SAL_CALL disposing( lang::EventObject const & rSource ) override;
105 inline void DisposingForwarder::listen(
106 Reference< lang::XComponent > const & xSource,
107 Reference< lang::XComponent > const & xTarget )
109 if (xSource.is())
111 xSource->addEventListener( new DisposingForwarder( xTarget ) );
115 void DisposingForwarder::disposing( lang::EventObject const & )
117 m_xTarget->dispose();
118 m_xTarget.clear();
121 namespace {
123 class ComponentContext
124 : public cppuhelper::WeakComponentImplHelper2< XComponentContext,
125 container::XNameContainer >
127 protected:
128 Reference< XComponentContext > m_xDelegate;
130 struct ContextEntry
132 Any value;
133 bool lateInit;
135 ContextEntry( Any value_, bool lateInit_ )
136 : value(std::move( value_ ))
137 , lateInit( lateInit_ )
140 typedef std::unordered_map< OUString, ContextEntry > t_map;
141 t_map m_map;
143 Reference< lang::XMultiComponentFactory > m_xSMgr;
145 protected:
146 Any lookupMap( OUString const & rName );
148 virtual void disposing(std::unique_lock<std::mutex>&) override;
149 public:
150 ComponentContext(
151 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
152 Reference< XComponentContext > const & xDelegate );
154 // XComponentContext
155 virtual Any SAL_CALL getValueByName( OUString const & rName ) override;
156 virtual Reference<lang::XMultiComponentFactory> SAL_CALL getServiceManager() override;
158 // XNameContainer
159 virtual void SAL_CALL insertByName(
160 OUString const & name, Any const & element ) override;
161 virtual void SAL_CALL removeByName( OUString const & name ) override;
162 // XNameReplace
163 virtual void SAL_CALL replaceByName(
164 OUString const & name, Any const & element ) override;
165 // XNameAccess
166 virtual Any SAL_CALL getByName( OUString const & name ) override;
167 virtual Sequence<OUString> SAL_CALL getElementNames() override;
168 virtual sal_Bool SAL_CALL hasByName( OUString const & name ) override;
169 // XElementAccess
170 virtual Type SAL_CALL getElementType() override;
171 virtual sal_Bool SAL_CALL hasElements() override;
176 // XNameContainer
178 void ComponentContext::insertByName(
179 OUString const & name, Any const & element )
181 ContextEntry entry(
182 element,
183 /* lateInit_: */
184 name.startsWith( "/singletons/" ) &&
185 !element.hasValue() );
186 std::unique_lock guard( m_aMutex );
187 std::pair<t_map::iterator, bool> insertion( m_map.emplace(
188 name, entry ) );
189 if (! insertion.second)
190 throw container::ElementExistException(
191 "element already exists: " + name,
192 static_cast<OWeakObject *>(this) );
196 void ComponentContext::removeByName( OUString const & name )
198 std::unique_lock guard( m_aMutex );
199 t_map::iterator iFind( m_map.find( name ) );
200 if (iFind == m_map.end())
201 throw container::NoSuchElementException(
202 "no such element: " + name,
203 static_cast<OWeakObject *>(this) );
205 m_map.erase(iFind);
208 // XNameReplace
210 void ComponentContext::replaceByName(
211 OUString const & name, Any const & element )
213 std::unique_lock guard( m_aMutex );
214 t_map::iterator iFind( m_map.find( name ) );
215 if (iFind == m_map.end())
216 throw container::NoSuchElementException(
217 "no such element: " + name,
218 static_cast<OWeakObject *>(this) );
219 if (name.startsWith( "/singletons/" ) &&
220 !element.hasValue())
222 iFind->second.value.clear();
223 iFind->second.lateInit = true;
225 else
227 iFind->second.value = element;
228 iFind->second.lateInit = false;
232 // XNameAccess
234 Any ComponentContext::getByName( OUString const & name )
236 return getValueByName( name );
240 Sequence<OUString> ComponentContext::getElementNames()
242 std::unique_lock guard( m_aMutex );
243 return comphelper::mapKeysToSequence(m_map);
247 sal_Bool ComponentContext::hasByName( OUString const & name )
249 std::unique_lock guard( m_aMutex );
250 return m_map.find( name ) != m_map.end();
253 // XElementAccess
255 Type ComponentContext::getElementType()
257 return cppu::UnoType<void>::get();
261 sal_Bool ComponentContext::hasElements()
263 std::unique_lock guard( m_aMutex );
264 return ! m_map.empty();
268 Any ComponentContext::lookupMap( OUString const & rName )
270 std::unique_lock guard( m_aMutex );
271 t_map::iterator iFind( m_map.find( rName ) );
272 if (iFind == m_map.end())
273 return Any();
275 ContextEntry& rFindEntry = iFind->second;
276 if (! rFindEntry.lateInit)
277 return rFindEntry.value;
279 // late init singleton entry
280 Reference< XInterface > xInstance;
281 guard.unlock();
285 Any usesService( getValueByName( rName + "/service" ) );
286 Any args_( getValueByName( rName + "/arguments" ) );
287 Sequence<Any> args;
288 if (args_.hasValue() && !(args_ >>= args))
290 args = { args_ };
293 Reference< lang::XSingleComponentFactory > xFac;
294 if (usesService >>= xFac) // try via factory
296 xInstance = args.hasElements()
297 ? xFac->createInstanceWithArgumentsAndContext( args, this )
298 : xFac->createInstanceWithContext( this );
300 else
302 Reference< lang::XSingleServiceFactory > xFac2;
303 if (usesService >>= xFac2)
305 // try via old XSingleServiceFactory
306 xInstance = args.hasElements()
307 ? xFac2->createInstanceWithArguments( args )
308 : xFac2->createInstance();
310 else if (m_xSMgr.is()) // optionally service name
312 OUString serviceName;
313 if ((usesService >>= serviceName) &&
314 !serviceName.isEmpty())
316 xInstance = args.hasElements()
317 ? m_xSMgr->createInstanceWithArgumentsAndContext(
318 serviceName, args, this )
319 : m_xSMgr->createInstanceWithContext(
320 serviceName, this );
325 catch (const RuntimeException &)
327 throw;
329 catch (const Exception & exc)
331 SAL_WARN(
332 "cppuhelper",
333 "exception occurred raising singleton \"" << rName << "\": "
334 << exc);
337 SAL_WARN_IF(!xInstance.is(),
338 "cppuhelper", "no service object raising singleton " << rName);
340 Any ret;
341 guard.lock();
342 iFind = m_map.find( rName );
343 if (iFind != m_map.end())
345 ContextEntry & rEntry = iFind->second;
346 if (rEntry.lateInit)
348 rEntry.value <<= xInstance;
349 rEntry.lateInit = false;
350 return rEntry.value;
352 ret = rEntry.value;
354 if (ret != xInstance) {
355 try_dispose( guard, xInstance );
357 return ret;
361 Any ComponentContext::getValueByName( OUString const & rName )
363 // to determine the root context:
364 if ( rName == "_root" )
366 if (m_xDelegate.is())
367 return m_xDelegate->getValueByName( rName );
368 return Any( Reference<XComponentContext>(this) );
371 Any ret( lookupMap( rName ) );
372 if (!ret.hasValue() && m_xDelegate.is())
374 return m_xDelegate->getValueByName( rName );
376 return ret;
379 Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
381 if ( !m_xSMgr.is() )
383 throw DeploymentException(
384 "null component context service manager",
385 static_cast<OWeakObject *>(this) );
387 return m_xSMgr;
390 void ComponentContext::disposing(std::unique_lock<std::mutex>& rGuard)
392 Reference< lang::XComponent > xTDMgr, xAC; // to be disposed separately
394 // dispose all context objects
395 for ( auto& [rName, rEntry] : m_map )
397 // service manager disposed separately
398 if (!m_xSMgr.is() ||
399 !rName.startsWith( SMGR_SINGLETON ))
401 if (rEntry.lateInit)
403 // late init
404 if (rEntry.lateInit)
406 rEntry.value.clear(); // release factory
407 rEntry.lateInit = false;
408 continue;
412 Reference< lang::XComponent > xComp;
413 rEntry.value >>= xComp;
414 if (xComp.is())
416 if ( rName == TDMGR_SINGLETON )
418 xTDMgr = xComp;
420 else if ( rName == AC_SINGLETON )
422 xAC = xComp;
424 else // dispose immediately
426 rGuard.unlock();
427 xComp->dispose();
428 rGuard.lock();
434 // dispose service manager
435 try_dispose( rGuard, m_xSMgr );
436 m_xSMgr.clear();
437 // dispose ac
438 try_dispose( rGuard, xAC );
439 // dispose tdmgr; revokes callback from cppu runtime
440 try_dispose( rGuard, xTDMgr );
442 m_map.clear();
444 // Hack to terminate any JNI bridge's AsynchronousFinalizer thread (as JNI
445 // proxies get finalized with arbitrary delay, so the bridge typically does
446 // not dispose itself early enough before the process exits):
447 uno_Environment ** envs;
448 sal_Int32 envCount;
449 uno_getRegisteredEnvironments(
450 &envs, &envCount, &rtl_allocateMemory, OUString("java").pData);
451 assert(envCount >= 0);
452 assert(envCount == 0 || envs != nullptr);
453 if (envs) {
454 for (sal_Int32 i = 0; i != envCount; ++i) {
455 assert(envs[i] != nullptr);
456 assert(envs[i]->dispose != nullptr);
457 (*envs[i]->dispose)(envs[i]);
459 std::free(envs);
463 ComponentContext::ComponentContext(
464 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
465 Reference< XComponentContext > const & xDelegate )
466 : m_xDelegate( xDelegate )
468 for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos )
470 ContextEntry_Init const & rEntry = pEntries[ nPos ];
472 if ( rEntry.name == SMGR_SINGLETON )
474 rEntry.value >>= m_xSMgr;
477 if (rEntry.bLateInitService)
479 // singleton entry
480 m_map.emplace( rEntry.name, ContextEntry( Any(), true ) );
481 // service
482 m_map.emplace( rEntry.name + "/service", ContextEntry( rEntry.value, false ) );
483 // initial-arguments are provided as optional context entry
485 else
487 // only value, no late init factory nor string
488 m_map.emplace( rEntry.name, ContextEntry( rEntry.value, false ) );
492 if (m_xSMgr.is() || !m_xDelegate.is())
493 return;
495 // wrap delegate's smgr XPropertySet into new smgr
496 Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() );
497 if (!xMgr.is())
498 return;
500 osl_atomic_increment( &m_refCount );
503 // create new smgr based on delegate's one
504 m_xSMgr.set(
505 xMgr->createInstanceWithContext(
506 "com.sun.star.comp.stoc.OServiceManagerWrapper", xDelegate ),
507 UNO_QUERY );
508 // patch DefaultContext property of new one
509 Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY );
510 OSL_ASSERT( xProps.is() );
511 if (xProps.is())
513 Reference< XComponentContext > xThis( this );
514 xProps->setPropertyValue( "DefaultContext", Any( xThis ) );
517 catch (...)
519 osl_atomic_decrement( &m_refCount );
520 throw;
522 osl_atomic_decrement( &m_refCount );
523 OSL_ASSERT( m_xSMgr.is() );
527 extern "C" { static void s_createComponentContext_v(va_list * pParam)
529 ContextEntry_Init const * pEntries = va_arg(*pParam, ContextEntry_Init const *);
530 sal_Int32 nEntries = va_arg(*pParam, sal_Int32);
531 XComponentContext * pDelegatee = va_arg(*pParam, XComponentContext *);
532 void ** ppContext = va_arg(*pParam, void **);
533 uno::Mapping * pTarget2curr = va_arg(*pParam, uno::Mapping *);
535 Reference<XComponentContext> xDelegate(pDelegatee, SAL_NO_ACQUIRE);
536 Reference<XComponentContext> xContext;
538 if (nEntries > 0)
542 ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate );
543 xContext.set(p);
544 // listen delegate for disposing, to dispose this (wrapping) context first.
545 DisposingForwarder::listen( Reference< lang::XComponent >::query( xDelegate ), p );
547 catch (Exception & exc)
549 SAL_WARN( "cppuhelper", exc );
550 xContext.clear();
553 else
555 xContext = xDelegate;
558 *ppContext = pTarget2curr->mapInterface(xContext.get(), cppu::UnoType<decltype(xContext)>::get());
561 Reference< XComponentContext > SAL_CALL createComponentContext(
562 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
563 Reference< XComponentContext > const & xDelegate )
565 uno::Environment curr_env(Environment::getCurrent());
566 uno::Environment source_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
568 uno::Mapping curr2source(curr_env, source_env);
569 uno::Mapping source2curr(source_env, curr_env);
571 std::unique_ptr<ContextEntry_Init[]> mapped_entries(new ContextEntry_Init[nEntries]);
572 for (sal_Int32 nPos = 0; nPos < nEntries; ++ nPos)
574 mapped_entries[nPos].bLateInitService = pEntries[nPos].bLateInitService;
575 mapped_entries[nPos].name = pEntries[nPos].name;
577 uno_type_any_constructAndConvert(&mapped_entries[nPos].value,
578 const_cast<void *>(pEntries[nPos].value.getValue()),
579 pEntries[nPos].value.getValueTypeRef(),
580 curr2source.get());
583 void * mapped_delegate = curr2source.mapInterface(xDelegate.get(), cppu::UnoType<decltype(xDelegate)>::get());
584 XComponentContext * pXComponentContext = nullptr;
585 source_env.invoke(s_createComponentContext_v, mapped_entries.get(), nEntries, mapped_delegate, &pXComponentContext, &source2curr);
586 mapped_entries.reset();
588 return Reference<XComponentContext>(pXComponentContext, SAL_NO_ACQUIRE);
593 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */