Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / cppuhelper / source / component_context.cxx
blob496e5ae75b1d172229fd6e65d3a06ebb31d9c1c6
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 <rtl/ustrbuf.hxx>
26 #include <sal/log.hxx>
28 #include <uno/lbnames.h>
29 #include <uno/mapping.hxx>
31 #include <cppuhelper/compbase.hxx>
32 #include <cppuhelper/component_context.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <cppuhelper/implbase.hxx>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
38 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
39 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
40 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
41 #include <com/sun/star/lang/XComponent.hpp>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/uno/DeploymentException.hpp>
44 #include <com/sun/star/uno/RuntimeException.hpp>
46 #include <memory>
48 #define SMGR_SINGLETON "/singletons/com.sun.star.lang.theServiceManager"
49 #define TDMGR_SINGLETON "/singletons/com.sun.star.reflection.theTypeDescriptionManager"
50 #define AC_SINGLETON "/singletons/com.sun.star.security.theAccessController"
52 using namespace ::osl;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star;
56 using rtl::OUString;
57 using rtl::OUStringBuffer;
59 namespace cppu
62 static inline void try_dispose( Reference< XInterface > const & xInstance )
64 Reference< lang::XComponent > xComp( xInstance, UNO_QUERY );
65 if (xComp.is())
67 xComp->dispose();
71 static inline void try_dispose( Reference< lang::XComponent > const & xComp )
73 if (xComp.is())
75 xComp->dispose();
79 class DisposingForwarder
80 : public WeakImplHelper< lang::XEventListener >
82 Reference< lang::XComponent > m_xTarget;
84 explicit DisposingForwarder( Reference< lang::XComponent > const & xTarget )
85 : m_xTarget( xTarget )
87 OSL_ASSERT( m_xTarget.is() );
89 public:
90 // listens at source for disposing, then disposes target
91 static inline void listen(
92 Reference< lang::XComponent > const & xSource,
93 Reference< lang::XComponent > const & xTarget );
95 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();
115 struct MutexHolder
117 protected:
118 Mutex m_mutex;
122 class ComponentContext
123 : private MutexHolder
124 , public WeakComponentImplHelper< XComponentContext,
125 container::XNameContainer >
127 protected:
128 Reference< XComponentContext > m_xDelegate;
130 struct ContextEntry
132 Any value;
133 bool lateInit;
135 ContextEntry( Any const & value_, bool lateInit_ )
136 : value( 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 SAL_CALL disposing() override;
149 public:
150 ComponentContext(
151 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
152 Reference< XComponentContext > const & xDelegate );
153 virtual ~ComponentContext() override;
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;
175 // XNameContainer
177 void ComponentContext::insertByName(
178 OUString const & name, Any const & element )
180 t_map::mapped_type entry(
181 new ContextEntry(
182 element,
183 /* lateInit_: */
184 name.startsWith( "/singletons/" ) &&
185 !element.hasValue() ) );
186 MutexGuard guard( m_mutex );
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 MutexGuard guard( m_mutex );
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 delete iFind->second;
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::const_iterator const 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 Sequence<OUString> ret( m_map.size() );
245 OUString * pret = ret.getArray();
246 sal_Int32 pos = 0;
247 t_map::const_iterator iPos( m_map.begin() );
248 t_map::const_iterator const iEnd( m_map.end() );
249 for ( ; iPos != iEnd; ++iPos )
250 pret[pos++] = iPos->first;
251 return ret;
255 sal_Bool ComponentContext::hasByName( OUString const & name )
257 MutexGuard guard( m_mutex );
258 return m_map.find( name ) != m_map.end();
261 // XElementAccess
263 Type ComponentContext::getElementType()
265 return cppu::UnoType<void>::get();
269 sal_Bool ComponentContext::hasElements()
271 MutexGuard guard( m_mutex );
272 return ! m_map.empty();
276 Any ComponentContext::lookupMap( OUString const & rName )
278 ResettableMutexGuard guard( m_mutex );
279 t_map::const_iterator iFind( m_map.find( rName ) );
280 if (iFind == m_map.end())
281 return Any();
283 t_map::mapped_type pEntry = iFind->second;
284 if (! pEntry->lateInit)
285 return pEntry->value;
287 // late init singleton entry
288 Reference< XInterface > xInstance;
289 guard.clear();
293 Any usesService( getValueByName( rName + "/service" ) );
294 Any args_( getValueByName( rName + "/arguments" ) );
295 Sequence<Any> args;
296 if (args_.hasValue() && !(args_ >>= args))
298 args.realloc( 1 );
299 args[ 0 ] = args_;
302 Reference< lang::XSingleComponentFactory > xFac;
303 if (usesService >>= xFac) // try via factory
305 xInstance = args.getLength()
306 ? xFac->createInstanceWithArgumentsAndContext( args, this )
307 : xFac->createInstanceWithContext( this );
309 else
311 Reference< lang::XSingleServiceFactory > xFac2;
312 if (usesService >>= xFac2)
314 // try via old XSingleServiceFactory
315 xInstance = args.getLength()
316 ? xFac2->createInstanceWithArguments( args )
317 : xFac2->createInstance();
319 else if (m_xSMgr.is()) // optionally service name
321 OUString serviceName;
322 if ((usesService >>= serviceName) &&
323 !serviceName.isEmpty())
325 xInstance = args.getLength()
326 ? m_xSMgr->createInstanceWithArgumentsAndContext(
327 serviceName, args, this )
328 : m_xSMgr->createInstanceWithContext(
329 serviceName, this );
334 catch (const RuntimeException &)
336 throw;
338 catch (const Exception & exc)
340 SAL_WARN(
341 "cppuhelper",
342 "exception occurred raising singleton \"" << rName << "\": "
343 << exc);
346 SAL_WARN_IF(!xInstance.is(),
347 "cppuhelper", "no service object raising singleton " << rName);
349 Any ret;
350 guard.reset();
351 iFind = m_map.find( rName );
352 if (iFind != m_map.end())
354 pEntry = iFind->second;
355 if (pEntry->lateInit)
357 pEntry->value <<= xInstance;
358 pEntry->lateInit = false;
359 return pEntry->value;
361 ret = pEntry->value;
363 guard.clear();
364 if (ret != xInstance) {
365 try_dispose( xInstance );
367 return ret;
371 Any ComponentContext::getValueByName( OUString const & rName )
373 // to determine the root context:
374 if ( rName == "_root" )
376 if (m_xDelegate.is())
377 return m_xDelegate->getValueByName( rName );
378 return Any( Reference<XComponentContext>(this) );
381 Any ret( lookupMap( rName ) );
382 if (!ret.hasValue() && m_xDelegate.is())
384 return m_xDelegate->getValueByName( rName );
386 return ret;
389 Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
391 if ( !m_xSMgr.is() )
393 throw DeploymentException(
394 "null component context service manager",
395 static_cast<OWeakObject *>(this) );
397 return m_xSMgr;
400 ComponentContext::~ComponentContext()
402 t_map::const_iterator iPos( m_map.begin() );
403 t_map::const_iterator const iEnd( m_map.end() );
404 for ( ; iPos != iEnd; ++iPos )
405 delete iPos->second;
406 m_map.clear();
409 void ComponentContext::disposing()
411 Reference< lang::XComponent > xTDMgr, xAC; // to be disposed separately
413 // dispose all context objects
414 t_map::const_iterator iPos( m_map.begin() );
415 t_map::const_iterator const iEnd( m_map.end() );
416 for ( ; iPos != iEnd; ++iPos )
418 t_map::mapped_type pEntry = iPos->second;
420 // service manager disposed separately
421 if (!m_xSMgr.is() ||
422 !iPos->first.startsWith( SMGR_SINGLETON ))
424 if (pEntry->lateInit)
426 // late init
427 MutexGuard guard( m_mutex );
428 if (pEntry->lateInit)
430 pEntry->value.clear(); // release factory
431 pEntry->lateInit = false;
432 continue;
436 Reference< lang::XComponent > xComp;
437 pEntry->value >>= xComp;
438 if (xComp.is())
440 if ( iPos->first == TDMGR_SINGLETON )
442 xTDMgr = xComp;
444 else if ( iPos->first == AC_SINGLETON )
446 xAC = xComp;
448 else // dispose immediately
450 xComp->dispose();
456 // dispose service manager
457 try_dispose( m_xSMgr );
458 m_xSMgr.clear();
459 // dispose ac
460 try_dispose( xAC );
461 // dispose tdmgr; revokes callback from cppu runtime
462 try_dispose( xTDMgr );
464 iPos = m_map.begin();
465 for ( ; iPos != iEnd; ++iPos )
466 delete iPos->second;
467 m_map.clear();
469 // Hack to terminate any JNI bridge's AsynchronousFinalizer thread (as JNI
470 // proxies get finalized with arbitrary delay, so the bridge typically does
471 // not dispose itself early enough before the process exits):
472 uno_Environment ** envs;
473 sal_Int32 envCount;
474 uno_getRegisteredEnvironments(
475 &envs, &envCount, &rtl_allocateMemory, OUString("java").pData);
476 assert(envCount >= 0);
477 assert(envCount == 0 || envs != nullptr);
478 if (envs) {
479 for (sal_Int32 i = 0; i != envCount; ++i) {
480 assert(envs[i] != nullptr);
481 assert(envs[i]->dispose != nullptr);
482 (*envs[i]->dispose)(envs[i]);
484 rtl_freeMemory(envs);
488 ComponentContext::ComponentContext(
489 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
490 Reference< XComponentContext > const & xDelegate )
491 : WeakComponentImplHelper( m_mutex ),
492 m_xDelegate( xDelegate )
494 for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos )
496 ContextEntry_Init const & rEntry = pEntries[ nPos ];
498 if ( rEntry.name == SMGR_SINGLETON )
500 rEntry.value >>= m_xSMgr;
503 if (rEntry.bLateInitService)
505 // singleton entry
506 m_map[ rEntry.name ] = new ContextEntry( Any(), true );
507 // service
508 m_map[ rEntry.name + "/service" ] = new ContextEntry( rEntry.value, false );
509 // initial-arguments are provided as optional context entry
511 else
513 // only value, no late init factory nor string
514 m_map[ rEntry.name ] = new ContextEntry( rEntry.value, false );
518 if (!m_xSMgr.is() && m_xDelegate.is())
520 // wrap delegate's smgr XPropertySet into new smgr
521 Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() );
522 if (xMgr.is())
524 osl_atomic_increment( &m_refCount );
527 // create new smgr based on delegate's one
528 m_xSMgr.set(
529 xMgr->createInstanceWithContext(
530 "com.sun.star.comp.stoc.OServiceManagerWrapper", xDelegate ),
531 UNO_QUERY );
532 // patch DefaultContext property of new one
533 Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY );
534 OSL_ASSERT( xProps.is() );
535 if (xProps.is())
537 Reference< XComponentContext > xThis( this );
538 xProps->setPropertyValue( "DefaultContext", Any( xThis ) );
541 catch (...)
543 osl_atomic_decrement( &m_refCount );
544 throw;
546 osl_atomic_decrement( &m_refCount );
547 OSL_ASSERT( m_xSMgr.is() );
553 extern "C" { static void s_createComponentContext_v(va_list * pParam)
555 ContextEntry_Init const * pEntries = va_arg(*pParam, ContextEntry_Init const *);
556 sal_Int32 nEntries = va_arg(*pParam, sal_Int32);
557 XComponentContext * pDelegatee = va_arg(*pParam, XComponentContext *);
558 void ** ppContext = va_arg(*pParam, void **);
559 uno::Mapping * pTarget2curr = va_arg(*pParam, uno::Mapping *);
561 Reference<XComponentContext> xDelegate(pDelegatee, SAL_NO_ACQUIRE);
562 Reference<XComponentContext> xContext;
564 if (nEntries > 0)
568 ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate );
569 xContext.set(p);
570 // listen delegate for disposing, to dispose this (wrapping) context first.
571 DisposingForwarder::listen( Reference< lang::XComponent >::query( xDelegate ), p );
573 catch (Exception & exc)
575 SAL_WARN( "cppuhelper", exc );
576 xContext.clear();
579 else
581 xContext = xDelegate;
584 *ppContext = pTarget2curr->mapInterface(xContext.get(), cppu::UnoType<decltype(xContext)>::get());
587 Reference< XComponentContext > SAL_CALL createComponentContext(
588 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
589 Reference< XComponentContext > const & xDelegate )
591 uno::Environment curr_env(Environment::getCurrent());
592 uno::Environment source_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
594 uno::Mapping curr2source(curr_env, source_env);
595 uno::Mapping source2curr(source_env, curr_env);
597 std::unique_ptr<ContextEntry_Init[]> mapped_entries(new ContextEntry_Init[nEntries]);
598 for (sal_Int32 nPos = 0; nPos < nEntries; ++ nPos)
600 mapped_entries[nPos].bLateInitService = pEntries[nPos].bLateInitService;
601 mapped_entries[nPos].name = pEntries[nPos].name;
603 uno_type_any_constructAndConvert(&mapped_entries[nPos].value,
604 const_cast<void *>(pEntries[nPos].value.getValue()),
605 pEntries[nPos].value.getValueTypeRef(),
606 curr2source.get());
609 void * mapped_delegate = curr2source.mapInterface(xDelegate.get(), cppu::UnoType<decltype(xDelegate)>::get());
610 XComponentContext * pXComponentContext = nullptr;
611 source_env.invoke(s_createComponentContext_v, mapped_entries.get(), nEntries, mapped_delegate, &pXComponentContext, &source2curr);
612 mapped_entries.reset();
614 return Reference<XComponentContext>(pXComponentContext, SAL_NO_ACQUIRE);
619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */