nss: makefile bitrot: no need for android spcial case anymore
[LibreOffice.git] / cppuhelper / source / component_context.cxx
blobc79bf6d12b2ed02180b077c295ed1f030e79242a
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 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.realloc( 1 );
292 args[ 0 ] = args_;
295 Reference< lang::XSingleComponentFactory > xFac;
296 if (usesService >>= xFac) // try via factory
298 xInstance = args.hasElements()
299 ? xFac->createInstanceWithArgumentsAndContext( args, this )
300 : xFac->createInstanceWithContext( this );
302 else
304 Reference< lang::XSingleServiceFactory > xFac2;
305 if (usesService >>= xFac2)
307 // try via old XSingleServiceFactory
308 xInstance = args.hasElements()
309 ? xFac2->createInstanceWithArguments( args )
310 : xFac2->createInstance();
312 else if (m_xSMgr.is()) // optionally service name
314 OUString serviceName;
315 if ((usesService >>= serviceName) &&
316 !serviceName.isEmpty())
318 xInstance = args.hasElements()
319 ? m_xSMgr->createInstanceWithArgumentsAndContext(
320 serviceName, args, this )
321 : m_xSMgr->createInstanceWithContext(
322 serviceName, this );
327 catch (const RuntimeException &)
329 throw;
331 catch (const Exception & exc)
333 SAL_WARN(
334 "cppuhelper",
335 "exception occurred raising singleton \"" << rName << "\": "
336 << exc);
339 SAL_WARN_IF(!xInstance.is(),
340 "cppuhelper", "no service object raising singleton " << rName);
342 Any ret;
343 guard.reset();
344 iFind = m_map.find( rName );
345 if (iFind != m_map.end())
347 ContextEntry & rEntry = iFind->second;
348 if (rEntry.lateInit)
350 rEntry.value <<= xInstance;
351 rEntry.lateInit = false;
352 return rEntry.value;
354 ret = rEntry.value;
356 guard.clear();
357 if (ret != xInstance) {
358 try_dispose( xInstance );
360 return ret;
364 Any ComponentContext::getValueByName( OUString const & rName )
366 // to determine the root context:
367 if ( rName == "_root" )
369 if (m_xDelegate.is())
370 return m_xDelegate->getValueByName( rName );
371 return Any( Reference<XComponentContext>(this) );
374 Any ret( lookupMap( rName ) );
375 if (!ret.hasValue() && m_xDelegate.is())
377 return m_xDelegate->getValueByName( rName );
379 return ret;
382 Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
384 if ( !m_xSMgr.is() )
386 throw DeploymentException(
387 "null component context service manager",
388 static_cast<OWeakObject *>(this) );
390 return m_xSMgr;
393 void ComponentContext::disposing()
395 Reference< lang::XComponent > xTDMgr, xAC; // to be disposed separately
397 // dispose all context objects
398 for ( auto& [rName, rEntry] : m_map )
400 // service manager disposed separately
401 if (!m_xSMgr.is() ||
402 !rName.startsWith( SMGR_SINGLETON ))
404 if (rEntry.lateInit)
406 // late init
407 MutexGuard guard( m_mutex );
408 if (rEntry.lateInit)
410 rEntry.value.clear(); // release factory
411 rEntry.lateInit = false;
412 continue;
416 Reference< lang::XComponent > xComp;
417 rEntry.value >>= xComp;
418 if (xComp.is())
420 if ( rName == TDMGR_SINGLETON )
422 xTDMgr = xComp;
424 else if ( rName == AC_SINGLETON )
426 xAC = xComp;
428 else // dispose immediately
430 xComp->dispose();
436 // dispose service manager
437 try_dispose( m_xSMgr );
438 m_xSMgr.clear();
439 // dispose ac
440 try_dispose( xAC );
441 // dispose tdmgr; revokes callback from cppu runtime
442 try_dispose( xTDMgr );
444 m_map.clear();
446 // Hack to terminate any JNI bridge's AsynchronousFinalizer thread (as JNI
447 // proxies get finalized with arbitrary delay, so the bridge typically does
448 // not dispose itself early enough before the process exits):
449 uno_Environment ** envs;
450 sal_Int32 envCount;
451 uno_getRegisteredEnvironments(
452 &envs, &envCount, &rtl_allocateMemory, OUString("java").pData);
453 assert(envCount >= 0);
454 assert(envCount == 0 || envs != nullptr);
455 if (envs) {
456 for (sal_Int32 i = 0; i != envCount; ++i) {
457 assert(envs[i] != nullptr);
458 assert(envs[i]->dispose != nullptr);
459 (*envs[i]->dispose)(envs[i]);
461 std::free(envs);
465 ComponentContext::ComponentContext(
466 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
467 Reference< XComponentContext > const & xDelegate )
468 : WeakComponentImplHelper( m_mutex ),
469 m_xDelegate( xDelegate )
471 for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos )
473 ContextEntry_Init const & rEntry = pEntries[ nPos ];
475 if ( rEntry.name == SMGR_SINGLETON )
477 rEntry.value >>= m_xSMgr;
480 if (rEntry.bLateInitService)
482 // singleton entry
483 m_map.emplace( rEntry.name, ContextEntry( Any(), true ) );
484 // service
485 m_map.emplace( rEntry.name + "/service", ContextEntry( rEntry.value, false ) );
486 // initial-arguments are provided as optional context entry
488 else
490 // only value, no late init factory nor string
491 m_map.emplace( rEntry.name, ContextEntry( rEntry.value, false ) );
495 if (m_xSMgr.is() || !m_xDelegate.is())
496 return;
498 // wrap delegate's smgr XPropertySet into new smgr
499 Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() );
500 if (!xMgr.is())
501 return;
503 osl_atomic_increment( &m_refCount );
506 // create new smgr based on delegate's one
507 m_xSMgr.set(
508 xMgr->createInstanceWithContext(
509 "com.sun.star.comp.stoc.OServiceManagerWrapper", xDelegate ),
510 UNO_QUERY );
511 // patch DefaultContext property of new one
512 Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY );
513 OSL_ASSERT( xProps.is() );
514 if (xProps.is())
516 Reference< XComponentContext > xThis( this );
517 xProps->setPropertyValue( "DefaultContext", Any( xThis ) );
520 catch (...)
522 osl_atomic_decrement( &m_refCount );
523 throw;
525 osl_atomic_decrement( &m_refCount );
526 OSL_ASSERT( m_xSMgr.is() );
530 extern "C" { static void s_createComponentContext_v(va_list * pParam)
532 ContextEntry_Init const * pEntries = va_arg(*pParam, ContextEntry_Init const *);
533 sal_Int32 nEntries = va_arg(*pParam, sal_Int32);
534 XComponentContext * pDelegatee = va_arg(*pParam, XComponentContext *);
535 void ** ppContext = va_arg(*pParam, void **);
536 uno::Mapping * pTarget2curr = va_arg(*pParam, uno::Mapping *);
538 Reference<XComponentContext> xDelegate(pDelegatee, SAL_NO_ACQUIRE);
539 Reference<XComponentContext> xContext;
541 if (nEntries > 0)
545 ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate );
546 xContext.set(p);
547 // listen delegate for disposing, to dispose this (wrapping) context first.
548 DisposingForwarder::listen( Reference< lang::XComponent >::query( xDelegate ), p );
550 catch (Exception & exc)
552 SAL_WARN( "cppuhelper", exc );
553 xContext.clear();
556 else
558 xContext = xDelegate;
561 *ppContext = pTarget2curr->mapInterface(xContext.get(), cppu::UnoType<decltype(xContext)>::get());
564 Reference< XComponentContext > SAL_CALL createComponentContext(
565 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
566 Reference< XComponentContext > const & xDelegate )
568 uno::Environment curr_env(Environment::getCurrent());
569 uno::Environment source_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
571 uno::Mapping curr2source(curr_env, source_env);
572 uno::Mapping source2curr(source_env, curr_env);
574 std::unique_ptr<ContextEntry_Init[]> mapped_entries(new ContextEntry_Init[nEntries]);
575 for (sal_Int32 nPos = 0; nPos < nEntries; ++ nPos)
577 mapped_entries[nPos].bLateInitService = pEntries[nPos].bLateInitService;
578 mapped_entries[nPos].name = pEntries[nPos].name;
580 uno_type_any_constructAndConvert(&mapped_entries[nPos].value,
581 const_cast<void *>(pEntries[nPos].value.getValue()),
582 pEntries[nPos].value.getValueTypeRef(),
583 curr2source.get());
586 void * mapped_delegate = curr2source.mapInterface(xDelegate.get(), cppu::UnoType<decltype(xDelegate)>::get());
587 XComponentContext * pXComponentContext = nullptr;
588 source_env.invoke(s_createComponentContext_v, mapped_entries.get(), nEntries, mapped_delegate, &pXComponentContext, &source2curr);
589 mapped_entries.reset();
591 return Reference<XComponentContext>(pXComponentContext, SAL_NO_ACQUIRE);
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */