Related: tdf#149490 OLE Object dialog should be modal
[LibreOffice.git] / cppuhelper / source / component_context.cxx
blob1aa3d33e5c3570ff85da0b860097436701124a6b
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 constexpr OUStringLiteral SMGR_SINGLETON = u"/singletons/com.sun.star.lang.theServiceManager";
48 constexpr OUStringLiteral TDMGR_SINGLETON = u"/singletons/com.sun.star.reflection.theTypeDescriptionManager";
49 constexpr OUStringLiteral AC_SINGLETON = u"/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 namespace {
77 class DisposingForwarder
78 : public WeakImplHelper< lang::XEventListener >
80 Reference< lang::XComponent > m_xTarget;
82 explicit DisposingForwarder( Reference< lang::XComponent > const & xTarget )
83 : m_xTarget( xTarget )
85 OSL_ASSERT( m_xTarget.is() );
87 public:
88 // listens at source for disposing, then disposes target
89 static inline void listen(
90 Reference< lang::XComponent > const & xSource,
91 Reference< lang::XComponent > const & xTarget );
93 virtual void SAL_CALL disposing( lang::EventObject const & rSource ) override;
98 inline void DisposingForwarder::listen(
99 Reference< lang::XComponent > const & xSource,
100 Reference< lang::XComponent > const & xTarget )
102 if (xSource.is())
104 xSource->addEventListener( new DisposingForwarder( xTarget ) );
108 void DisposingForwarder::disposing( lang::EventObject const & )
110 m_xTarget->dispose();
111 m_xTarget.clear();
114 namespace {
116 struct MutexHolder
118 protected:
119 Mutex m_mutex;
123 class ComponentContext
124 : private MutexHolder
125 , public WeakComponentImplHelper< XComponentContext,
126 container::XNameContainer >
128 protected:
129 Reference< XComponentContext > m_xDelegate;
131 struct ContextEntry
133 Any value;
134 bool lateInit;
136 ContextEntry( Any const & value_, bool lateInit_ )
137 : value( value_ )
138 , lateInit( lateInit_ )
141 typedef std::unordered_map< OUString, ContextEntry > t_map;
142 t_map m_map;
144 Reference< lang::XMultiComponentFactory > m_xSMgr;
146 protected:
147 Any lookupMap( OUString const & rName );
149 virtual void SAL_CALL disposing() override;
150 public:
151 ComponentContext(
152 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
153 Reference< XComponentContext > const & xDelegate );
155 // XComponentContext
156 virtual Any SAL_CALL getValueByName( OUString const & rName ) override;
157 virtual Reference<lang::XMultiComponentFactory> SAL_CALL getServiceManager() override;
159 // XNameContainer
160 virtual void SAL_CALL insertByName(
161 OUString const & name, Any const & element ) override;
162 virtual void SAL_CALL removeByName( OUString const & name ) override;
163 // XNameReplace
164 virtual void SAL_CALL replaceByName(
165 OUString const & name, Any const & element ) override;
166 // XNameAccess
167 virtual Any SAL_CALL getByName( OUString const & name ) override;
168 virtual Sequence<OUString> SAL_CALL getElementNames() override;
169 virtual sal_Bool SAL_CALL hasByName( OUString const & name ) override;
170 // XElementAccess
171 virtual Type SAL_CALL getElementType() override;
172 virtual sal_Bool SAL_CALL hasElements() override;
177 // XNameContainer
179 void ComponentContext::insertByName(
180 OUString const & name, Any const & element )
182 ContextEntry entry(
183 element,
184 /* lateInit_: */
185 name.startsWith( "/singletons/" ) &&
186 !element.hasValue() );
187 MutexGuard guard( m_mutex );
188 std::pair<t_map::iterator, bool> insertion( m_map.emplace(
189 name, entry ) );
190 if (! insertion.second)
191 throw container::ElementExistException(
192 "element already exists: " + name,
193 static_cast<OWeakObject *>(this) );
197 void ComponentContext::removeByName( OUString const & name )
199 MutexGuard guard( m_mutex );
200 t_map::iterator iFind( m_map.find( name ) );
201 if (iFind == m_map.end())
202 throw container::NoSuchElementException(
203 "no such element: " + name,
204 static_cast<OWeakObject *>(this) );
206 m_map.erase(iFind);
209 // XNameReplace
211 void ComponentContext::replaceByName(
212 OUString const & name, Any const & element )
214 MutexGuard guard( m_mutex );
215 t_map::iterator iFind( m_map.find( name ) );
216 if (iFind == m_map.end())
217 throw container::NoSuchElementException(
218 "no such element: " + name,
219 static_cast<OWeakObject *>(this) );
220 if (name.startsWith( "/singletons/" ) &&
221 !element.hasValue())
223 iFind->second.value.clear();
224 iFind->second.lateInit = true;
226 else
228 iFind->second.value = element;
229 iFind->second.lateInit = false;
233 // XNameAccess
235 Any ComponentContext::getByName( OUString const & name )
237 return getValueByName( name );
241 Sequence<OUString> ComponentContext::getElementNames()
243 MutexGuard guard( m_mutex );
244 return comphelper::mapKeysToSequence(m_map);
248 sal_Bool ComponentContext::hasByName( OUString const & name )
250 MutexGuard guard( m_mutex );
251 return m_map.find( name ) != m_map.end();
254 // XElementAccess
256 Type ComponentContext::getElementType()
258 return cppu::UnoType<void>::get();
262 sal_Bool ComponentContext::hasElements()
264 MutexGuard guard( m_mutex );
265 return ! m_map.empty();
269 Any ComponentContext::lookupMap( OUString const & rName )
271 ResettableMutexGuard guard( m_mutex );
272 t_map::iterator iFind( m_map.find( rName ) );
273 if (iFind == m_map.end())
274 return Any();
276 ContextEntry& rFindEntry = iFind->second;
277 if (! rFindEntry.lateInit)
278 return rFindEntry.value;
280 // late init singleton entry
281 Reference< XInterface > xInstance;
282 guard.clear();
286 Any usesService( getValueByName( rName + "/service" ) );
287 Any args_( getValueByName( rName + "/arguments" ) );
288 Sequence<Any> args;
289 if (args_.hasValue() && !(args_ >>= args))
291 args = { args_ };
294 Reference< lang::XSingleComponentFactory > xFac;
295 if (usesService >>= xFac) // try via factory
297 xInstance = args.hasElements()
298 ? xFac->createInstanceWithArgumentsAndContext( args, this )
299 : xFac->createInstanceWithContext( this );
301 else
303 Reference< lang::XSingleServiceFactory > xFac2;
304 if (usesService >>= xFac2)
306 // try via old XSingleServiceFactory
307 xInstance = args.hasElements()
308 ? xFac2->createInstanceWithArguments( args )
309 : xFac2->createInstance();
311 else if (m_xSMgr.is()) // optionally service name
313 OUString serviceName;
314 if ((usesService >>= serviceName) &&
315 !serviceName.isEmpty())
317 xInstance = args.hasElements()
318 ? m_xSMgr->createInstanceWithArgumentsAndContext(
319 serviceName, args, this )
320 : m_xSMgr->createInstanceWithContext(
321 serviceName, this );
326 catch (const RuntimeException &)
328 throw;
330 catch (const Exception & exc)
332 SAL_WARN(
333 "cppuhelper",
334 "exception occurred raising singleton \"" << rName << "\": "
335 << exc);
338 SAL_WARN_IF(!xInstance.is(),
339 "cppuhelper", "no service object raising singleton " << rName);
341 Any ret;
342 guard.reset();
343 iFind = m_map.find( rName );
344 if (iFind != m_map.end())
346 ContextEntry & rEntry = iFind->second;
347 if (rEntry.lateInit)
349 rEntry.value <<= xInstance;
350 rEntry.lateInit = false;
351 return rEntry.value;
353 ret = rEntry.value;
355 guard.clear();
356 if (ret != xInstance) {
357 try_dispose( xInstance );
359 return ret;
363 Any ComponentContext::getValueByName( OUString const & rName )
365 // to determine the root context:
366 if ( rName == "_root" )
368 if (m_xDelegate.is())
369 return m_xDelegate->getValueByName( rName );
370 return Any( Reference<XComponentContext>(this) );
373 Any ret( lookupMap( rName ) );
374 if (!ret.hasValue() && m_xDelegate.is())
376 return m_xDelegate->getValueByName( rName );
378 return ret;
381 Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
383 if ( !m_xSMgr.is() )
385 throw DeploymentException(
386 "null component context service manager",
387 static_cast<OWeakObject *>(this) );
389 return m_xSMgr;
392 void ComponentContext::disposing()
394 Reference< lang::XComponent > xTDMgr, xAC; // to be disposed separately
396 // dispose all context objects
397 for ( auto& [rName, rEntry] : m_map )
399 // service manager disposed separately
400 if (!m_xSMgr.is() ||
401 !rName.startsWith( SMGR_SINGLETON ))
403 if (rEntry.lateInit)
405 // late init
406 MutexGuard guard( m_mutex );
407 if (rEntry.lateInit)
409 rEntry.value.clear(); // release factory
410 rEntry.lateInit = false;
411 continue;
415 Reference< lang::XComponent > xComp;
416 rEntry.value >>= xComp;
417 if (xComp.is())
419 if ( rName == TDMGR_SINGLETON )
421 xTDMgr = xComp;
423 else if ( rName == AC_SINGLETON )
425 xAC = xComp;
427 else // dispose immediately
429 xComp->dispose();
435 // dispose service manager
436 try_dispose( m_xSMgr );
437 m_xSMgr.clear();
438 // dispose ac
439 try_dispose( xAC );
440 // dispose tdmgr; revokes callback from cppu runtime
441 try_dispose( xTDMgr );
443 m_map.clear();
445 // Hack to terminate any JNI bridge's AsynchronousFinalizer thread (as JNI
446 // proxies get finalized with arbitrary delay, so the bridge typically does
447 // not dispose itself early enough before the process exits):
448 uno_Environment ** envs;
449 sal_Int32 envCount;
450 uno_getRegisteredEnvironments(
451 &envs, &envCount, &rtl_allocateMemory, OUString("java").pData);
452 assert(envCount >= 0);
453 assert(envCount == 0 || envs != nullptr);
454 if (envs) {
455 for (sal_Int32 i = 0; i != envCount; ++i) {
456 assert(envs[i] != nullptr);
457 assert(envs[i]->dispose != nullptr);
458 (*envs[i]->dispose)(envs[i]);
460 std::free(envs);
464 ComponentContext::ComponentContext(
465 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
466 Reference< XComponentContext > const & xDelegate )
467 : WeakComponentImplHelper( m_mutex ),
468 m_xDelegate( xDelegate )
470 for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos )
472 ContextEntry_Init const & rEntry = pEntries[ nPos ];
474 if ( rEntry.name == SMGR_SINGLETON )
476 rEntry.value >>= m_xSMgr;
479 if (rEntry.bLateInitService)
481 // singleton entry
482 m_map.emplace( rEntry.name, ContextEntry( Any(), true ) );
483 // service
484 m_map.emplace( rEntry.name + "/service", ContextEntry( rEntry.value, false ) );
485 // initial-arguments are provided as optional context entry
487 else
489 // only value, no late init factory nor string
490 m_map.emplace( rEntry.name, ContextEntry( rEntry.value, false ) );
494 if (m_xSMgr.is() || !m_xDelegate.is())
495 return;
497 // wrap delegate's smgr XPropertySet into new smgr
498 Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() );
499 if (!xMgr.is())
500 return;
502 osl_atomic_increment( &m_refCount );
505 // create new smgr based on delegate's one
506 m_xSMgr.set(
507 xMgr->createInstanceWithContext(
508 "com.sun.star.comp.stoc.OServiceManagerWrapper", xDelegate ),
509 UNO_QUERY );
510 // patch DefaultContext property of new one
511 Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY );
512 OSL_ASSERT( xProps.is() );
513 if (xProps.is())
515 Reference< XComponentContext > xThis( this );
516 xProps->setPropertyValue( "DefaultContext", Any( xThis ) );
519 catch (...)
521 osl_atomic_decrement( &m_refCount );
522 throw;
524 osl_atomic_decrement( &m_refCount );
525 OSL_ASSERT( m_xSMgr.is() );
529 extern "C" { static void s_createComponentContext_v(va_list * pParam)
531 ContextEntry_Init const * pEntries = va_arg(*pParam, ContextEntry_Init const *);
532 sal_Int32 nEntries = va_arg(*pParam, sal_Int32);
533 XComponentContext * pDelegatee = va_arg(*pParam, XComponentContext *);
534 void ** ppContext = va_arg(*pParam, void **);
535 uno::Mapping * pTarget2curr = va_arg(*pParam, uno::Mapping *);
537 Reference<XComponentContext> xDelegate(pDelegatee, SAL_NO_ACQUIRE);
538 Reference<XComponentContext> xContext;
540 if (nEntries > 0)
544 ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate );
545 xContext.set(p);
546 // listen delegate for disposing, to dispose this (wrapping) context first.
547 DisposingForwarder::listen( Reference< lang::XComponent >::query( xDelegate ), p );
549 catch (Exception & exc)
551 SAL_WARN( "cppuhelper", exc );
552 xContext.clear();
555 else
557 xContext = xDelegate;
560 *ppContext = pTarget2curr->mapInterface(xContext.get(), cppu::UnoType<decltype(xContext)>::get());
563 Reference< XComponentContext > SAL_CALL createComponentContext(
564 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
565 Reference< XComponentContext > const & xDelegate )
567 uno::Environment curr_env(Environment::getCurrent());
568 uno::Environment source_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
570 uno::Mapping curr2source(curr_env, source_env);
571 uno::Mapping source2curr(source_env, curr_env);
573 std::unique_ptr<ContextEntry_Init[]> mapped_entries(new ContextEntry_Init[nEntries]);
574 for (sal_Int32 nPos = 0; nPos < nEntries; ++ nPos)
576 mapped_entries[nPos].bLateInitService = pEntries[nPos].bLateInitService;
577 mapped_entries[nPos].name = pEntries[nPos].name;
579 uno_type_any_constructAndConvert(&mapped_entries[nPos].value,
580 const_cast<void *>(pEntries[nPos].value.getValue()),
581 pEntries[nPos].value.getValueTypeRef(),
582 curr2source.get());
585 void * mapped_delegate = curr2source.mapInterface(xDelegate.get(), cppu::UnoType<decltype(xDelegate)>::get());
586 XComponentContext * pXComponentContext = nullptr;
587 source_env.invoke(s_createComponentContext_v, mapped_entries.get(), nEntries, mapped_delegate, &pXComponentContext, &source2curr);
588 mapped_entries.reset();
590 return Reference<XComponentContext>(pXComponentContext, SAL_NO_ACQUIRE);
595 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */