Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / cppuhelper / source / component_context.cxx
blob5d6294704f7fdd218c0f2227bdd6c6630a8a08dd
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/compbase.hxx>
31 #include <cppuhelper/component_context.hxx>
32 #include <cppuhelper/implbase.hxx>
34 #include <com/sun/star/container/XNameContainer.hpp>
35 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
36 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
37 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
38 #include <com/sun/star/lang/XComponent.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/uno/DeploymentException.hpp>
41 #include <com/sun/star/uno/RuntimeException.hpp>
43 #include <comphelper/sequence.hxx>
45 #include <memory>
47 #define SMGR_SINGLETON "/singletons/com.sun.star.lang.theServiceManager"
48 #define TDMGR_SINGLETON "/singletons/com.sun.star.reflection.theTypeDescriptionManager"
49 #define AC_SINGLETON "/singletons/com.sun.star.security.theAccessController"
51 using namespace ::osl;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star;
55 namespace cppu
58 static void try_dispose( Reference< XInterface > const & xInstance )
60 Reference< lang::XComponent > xComp( xInstance, UNO_QUERY );
61 if (xComp.is())
63 xComp->dispose();
67 static void try_dispose( Reference< lang::XComponent > const & xComp )
69 if (xComp.is())
71 xComp->dispose();
75 class DisposingForwarder
76 : public WeakImplHelper< lang::XEventListener >
78 Reference< lang::XComponent > m_xTarget;
80 explicit DisposingForwarder( Reference< lang::XComponent > const & xTarget )
81 : m_xTarget( xTarget )
83 OSL_ASSERT( m_xTarget.is() );
85 public:
86 // listens at source for disposing, then disposes target
87 static inline void listen(
88 Reference< lang::XComponent > const & xSource,
89 Reference< lang::XComponent > const & xTarget );
91 virtual void SAL_CALL disposing( lang::EventObject const & rSource ) override;
94 inline void DisposingForwarder::listen(
95 Reference< lang::XComponent > const & xSource,
96 Reference< lang::XComponent > const & xTarget )
98 if (xSource.is())
100 xSource->addEventListener( new DisposingForwarder( xTarget ) );
104 void DisposingForwarder::disposing( lang::EventObject const & )
106 m_xTarget->dispose();
107 m_xTarget.clear();
111 struct MutexHolder
113 protected:
114 Mutex m_mutex;
118 class ComponentContext
119 : private MutexHolder
120 , public WeakComponentImplHelper< XComponentContext,
121 container::XNameContainer >
123 protected:
124 Reference< XComponentContext > m_xDelegate;
126 struct ContextEntry
128 Any value;
129 bool lateInit;
131 ContextEntry( Any const & value_, bool lateInit_ )
132 : value( value_ )
133 , lateInit( lateInit_ )
136 typedef std::unordered_map< OUString, ContextEntry > t_map;
137 t_map m_map;
139 Reference< lang::XMultiComponentFactory > m_xSMgr;
141 protected:
142 Any lookupMap( OUString const & rName );
144 virtual void SAL_CALL disposing() override;
145 public:
146 ComponentContext(
147 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
148 Reference< XComponentContext > const & xDelegate );
150 // XComponentContext
151 virtual Any SAL_CALL getValueByName( OUString const & rName ) override;
152 virtual Reference<lang::XMultiComponentFactory> SAL_CALL getServiceManager() override;
154 // XNameContainer
155 virtual void SAL_CALL insertByName(
156 OUString const & name, Any const & element ) override;
157 virtual void SAL_CALL removeByName( OUString const & name ) override;
158 // XNameReplace
159 virtual void SAL_CALL replaceByName(
160 OUString const & name, Any const & element ) override;
161 // XNameAccess
162 virtual Any SAL_CALL getByName( OUString const & name ) override;
163 virtual Sequence<OUString> SAL_CALL getElementNames() override;
164 virtual sal_Bool SAL_CALL hasByName( OUString const & name ) override;
165 // XElementAccess
166 virtual Type SAL_CALL getElementType() override;
167 virtual sal_Bool SAL_CALL hasElements() override;
170 // XNameContainer
172 void ComponentContext::insertByName(
173 OUString const & name, Any const & element )
175 ContextEntry entry(
176 element,
177 /* lateInit_: */
178 name.startsWith( "/singletons/" ) &&
179 !element.hasValue() );
180 MutexGuard guard( m_mutex );
181 std::pair<t_map::iterator, bool> insertion( m_map.emplace(
182 name, entry ) );
183 if (! insertion.second)
184 throw container::ElementExistException(
185 "element already exists: " + name,
186 static_cast<OWeakObject *>(this) );
190 void ComponentContext::removeByName( OUString const & name )
192 MutexGuard guard( m_mutex );
193 t_map::iterator iFind( m_map.find( name ) );
194 if (iFind == m_map.end())
195 throw container::NoSuchElementException(
196 "no such element: " + name,
197 static_cast<OWeakObject *>(this) );
199 m_map.erase(iFind);
202 // XNameReplace
204 void ComponentContext::replaceByName(
205 OUString const & name, Any const & element )
207 MutexGuard guard( m_mutex );
208 t_map::iterator iFind( m_map.find( name ) );
209 if (iFind == m_map.end())
210 throw container::NoSuchElementException(
211 "no such element: " + name,
212 static_cast<OWeakObject *>(this) );
213 if (name.startsWith( "/singletons/" ) &&
214 !element.hasValue())
216 iFind->second.value.clear();
217 iFind->second.lateInit = true;
219 else
221 iFind->second.value = element;
222 iFind->second.lateInit = false;
226 // XNameAccess
228 Any ComponentContext::getByName( OUString const & name )
230 return getValueByName( name );
234 Sequence<OUString> ComponentContext::getElementNames()
236 MutexGuard guard( m_mutex );
237 return comphelper::mapKeysToSequence(m_map);
241 sal_Bool ComponentContext::hasByName( OUString const & name )
243 MutexGuard guard( m_mutex );
244 return m_map.find( name ) != m_map.end();
247 // XElementAccess
249 Type ComponentContext::getElementType()
251 return cppu::UnoType<void>::get();
255 sal_Bool ComponentContext::hasElements()
257 MutexGuard guard( m_mutex );
258 return ! m_map.empty();
262 Any ComponentContext::lookupMap( OUString const & rName )
264 ResettableMutexGuard guard( m_mutex );
265 t_map::iterator iFind( m_map.find( rName ) );
266 if (iFind == m_map.end())
267 return Any();
269 ContextEntry& rFindEntry = iFind->second;
270 if (! rFindEntry.lateInit)
271 return rFindEntry.value;
273 // late init singleton entry
274 Reference< XInterface > xInstance;
275 guard.clear();
279 Any usesService( getValueByName( rName + "/service" ) );
280 Any args_( getValueByName( rName + "/arguments" ) );
281 Sequence<Any> args;
282 if (args_.hasValue() && !(args_ >>= args))
284 args.realloc( 1 );
285 args[ 0 ] = args_;
288 Reference< lang::XSingleComponentFactory > xFac;
289 if (usesService >>= xFac) // try via factory
291 xInstance = args.hasElements()
292 ? xFac->createInstanceWithArgumentsAndContext( args, this )
293 : xFac->createInstanceWithContext( this );
295 else
297 Reference< lang::XSingleServiceFactory > xFac2;
298 if (usesService >>= xFac2)
300 // try via old XSingleServiceFactory
301 xInstance = args.hasElements()
302 ? xFac2->createInstanceWithArguments( args )
303 : xFac2->createInstance();
305 else if (m_xSMgr.is()) // optionally service name
307 OUString serviceName;
308 if ((usesService >>= serviceName) &&
309 !serviceName.isEmpty())
311 xInstance = args.hasElements()
312 ? m_xSMgr->createInstanceWithArgumentsAndContext(
313 serviceName, args, this )
314 : m_xSMgr->createInstanceWithContext(
315 serviceName, this );
320 catch (const RuntimeException &)
322 throw;
324 catch (const Exception & exc)
326 SAL_WARN(
327 "cppuhelper",
328 "exception occurred raising singleton \"" << rName << "\": "
329 << exc);
332 SAL_WARN_IF(!xInstance.is(),
333 "cppuhelper", "no service object raising singleton " << rName);
335 Any ret;
336 guard.reset();
337 iFind = m_map.find( rName );
338 if (iFind != m_map.end())
340 ContextEntry & rEntry = iFind->second;
341 if (rEntry.lateInit)
343 rEntry.value <<= xInstance;
344 rEntry.lateInit = false;
345 return rEntry.value;
347 ret = rEntry.value;
349 guard.clear();
350 if (ret != xInstance) {
351 try_dispose( xInstance );
353 return ret;
357 Any ComponentContext::getValueByName( OUString const & rName )
359 // to determine the root context:
360 if ( rName == "_root" )
362 if (m_xDelegate.is())
363 return m_xDelegate->getValueByName( rName );
364 return Any( Reference<XComponentContext>(this) );
367 Any ret( lookupMap( rName ) );
368 if (!ret.hasValue() && m_xDelegate.is())
370 return m_xDelegate->getValueByName( rName );
372 return ret;
375 Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
377 if ( !m_xSMgr.is() )
379 throw DeploymentException(
380 "null component context service manager",
381 static_cast<OWeakObject *>(this) );
383 return m_xSMgr;
386 void ComponentContext::disposing()
388 Reference< lang::XComponent > xTDMgr, xAC; // to be disposed separately
390 // dispose all context objects
391 for ( auto& [rName, rEntry] : m_map )
393 // service manager disposed separately
394 if (!m_xSMgr.is() ||
395 !rName.startsWith( SMGR_SINGLETON ))
397 if (rEntry.lateInit)
399 // late init
400 MutexGuard guard( m_mutex );
401 if (rEntry.lateInit)
403 rEntry.value.clear(); // release factory
404 rEntry.lateInit = false;
405 continue;
409 Reference< lang::XComponent > xComp;
410 rEntry.value >>= xComp;
411 if (xComp.is())
413 if ( rName == TDMGR_SINGLETON )
415 xTDMgr = xComp;
417 else if ( rName == AC_SINGLETON )
419 xAC = xComp;
421 else // dispose immediately
423 xComp->dispose();
429 // dispose service manager
430 try_dispose( m_xSMgr );
431 m_xSMgr.clear();
432 // dispose ac
433 try_dispose( xAC );
434 // dispose tdmgr; revokes callback from cppu runtime
435 try_dispose( 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, OUString("java").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 : WeakComponentImplHelper( m_mutex ),
462 m_xDelegate( xDelegate )
464 for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos )
466 ContextEntry_Init const & rEntry = pEntries[ nPos ];
468 if ( rEntry.name == SMGR_SINGLETON )
470 rEntry.value >>= m_xSMgr;
473 if (rEntry.bLateInitService)
475 // singleton entry
476 m_map.emplace( rEntry.name, ContextEntry( Any(), true ) );
477 // service
478 m_map.emplace( rEntry.name + "/service", ContextEntry( rEntry.value, false ) );
479 // initial-arguments are provided as optional context entry
481 else
483 // only value, no late init factory nor string
484 m_map.emplace( rEntry.name, ContextEntry( rEntry.value, false ) );
488 if (!m_xSMgr.is() && m_xDelegate.is())
490 // wrap delegate's smgr XPropertySet into new smgr
491 Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() );
492 if (xMgr.is())
494 osl_atomic_increment( &m_refCount );
497 // create new smgr based on delegate's one
498 m_xSMgr.set(
499 xMgr->createInstanceWithContext(
500 "com.sun.star.comp.stoc.OServiceManagerWrapper", xDelegate ),
501 UNO_QUERY );
502 // patch DefaultContext property of new one
503 Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY );
504 OSL_ASSERT( xProps.is() );
505 if (xProps.is())
507 Reference< XComponentContext > xThis( this );
508 xProps->setPropertyValue( "DefaultContext", Any( xThis ) );
511 catch (...)
513 osl_atomic_decrement( &m_refCount );
514 throw;
516 osl_atomic_decrement( &m_refCount );
517 OSL_ASSERT( m_xSMgr.is() );
523 extern "C" { static void s_createComponentContext_v(va_list * pParam)
525 ContextEntry_Init const * pEntries = va_arg(*pParam, ContextEntry_Init const *);
526 sal_Int32 nEntries = va_arg(*pParam, sal_Int32);
527 XComponentContext * pDelegatee = va_arg(*pParam, XComponentContext *);
528 void ** ppContext = va_arg(*pParam, void **);
529 uno::Mapping * pTarget2curr = va_arg(*pParam, uno::Mapping *);
531 Reference<XComponentContext> xDelegate(pDelegatee, SAL_NO_ACQUIRE);
532 Reference<XComponentContext> xContext;
534 if (nEntries > 0)
538 ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate );
539 xContext.set(p);
540 // listen delegate for disposing, to dispose this (wrapping) context first.
541 DisposingForwarder::listen( Reference< lang::XComponent >::query( xDelegate ), p );
543 catch (Exception & exc)
545 SAL_WARN( "cppuhelper", exc );
546 xContext.clear();
549 else
551 xContext = xDelegate;
554 *ppContext = pTarget2curr->mapInterface(xContext.get(), cppu::UnoType<decltype(xContext)>::get());
557 Reference< XComponentContext > SAL_CALL createComponentContext(
558 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
559 Reference< XComponentContext > const & xDelegate )
561 uno::Environment curr_env(Environment::getCurrent());
562 uno::Environment source_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
564 uno::Mapping curr2source(curr_env, source_env);
565 uno::Mapping source2curr(source_env, curr_env);
567 std::unique_ptr<ContextEntry_Init[]> mapped_entries(new ContextEntry_Init[nEntries]);
568 for (sal_Int32 nPos = 0; nPos < nEntries; ++ nPos)
570 mapped_entries[nPos].bLateInitService = pEntries[nPos].bLateInitService;
571 mapped_entries[nPos].name = pEntries[nPos].name;
573 uno_type_any_constructAndConvert(&mapped_entries[nPos].value,
574 const_cast<void *>(pEntries[nPos].value.getValue()),
575 pEntries[nPos].value.getValueTypeRef(),
576 curr2source.get());
579 void * mapped_delegate = curr2source.mapInterface(xDelegate.get(), cppu::UnoType<decltype(xDelegate)>::get());
580 XComponentContext * pXComponentContext = nullptr;
581 source_env.invoke(s_createComponentContext_v, mapped_entries.get(), nEntries, mapped_delegate, &pXComponentContext, &source2curr);
582 mapped_entries.reset();
584 return Reference<XComponentContext>(pXComponentContext, SAL_NO_ACQUIRE);
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */