1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
57 using rtl::OUStringBuffer
;
62 static inline void try_dispose( Reference
< XInterface
> const & xInstance
)
64 Reference
< lang::XComponent
> xComp( xInstance
, UNO_QUERY
);
71 static inline void try_dispose( Reference
< lang::XComponent
> const & xComp
)
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() );
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
)
104 xSource
->addEventListener( new DisposingForwarder( xTarget
) );
108 void DisposingForwarder::disposing( lang::EventObject
const & )
110 m_xTarget
->dispose();
122 class ComponentContext
123 : private MutexHolder
124 , public WeakComponentImplHelper
< XComponentContext
,
125 container::XNameContainer
>
128 Reference
< XComponentContext
> m_xDelegate
;
135 ContextEntry( Any
const & value_
, bool lateInit_
)
137 , lateInit( lateInit_
)
140 typedef std::unordered_map
< OUString
, ContextEntry
* > t_map
;
143 Reference
< lang::XMultiComponentFactory
> m_xSMgr
;
146 Any
lookupMap( OUString
const & rName
);
148 virtual void SAL_CALL
disposing() override
;
151 ContextEntry_Init
const * pEntries
, sal_Int32 nEntries
,
152 Reference
< XComponentContext
> const & xDelegate
);
153 virtual ~ComponentContext() override
;
156 virtual Any SAL_CALL
getValueByName( OUString
const & rName
) override
;
157 virtual Reference
<lang::XMultiComponentFactory
> SAL_CALL
getServiceManager() override
;
160 virtual void SAL_CALL
insertByName(
161 OUString
const & name
, Any
const & element
) override
;
162 virtual void SAL_CALL
removeByName( OUString
const & name
) override
;
164 virtual void SAL_CALL
replaceByName(
165 OUString
const & name
, Any
const & element
) override
;
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
;
171 virtual Type SAL_CALL
getElementType() override
;
172 virtual sal_Bool SAL_CALL
hasElements() override
;
177 void ComponentContext::insertByName(
178 OUString
const & name
, Any
const & element
)
180 t_map::mapped_type
entry(
184 name
.startsWith( "/singletons/" ) &&
185 !element
.hasValue() ) );
186 MutexGuard
guard( m_mutex
);
187 std::pair
<t_map::iterator
, bool> insertion( m_map
.emplace(
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
;
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/" ) &&
223 iFind
->second
->value
.clear();
224 iFind
->second
->lateInit
= true;
228 iFind
->second
->value
= element
;
229 iFind
->second
->lateInit
= false;
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();
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
;
255 sal_Bool
ComponentContext::hasByName( OUString
const & name
)
257 MutexGuard
guard( m_mutex
);
258 return m_map
.find( name
) != m_map
.end();
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())
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
;
293 Any
usesService( getValueByName( rName
+ "/service" ) );
294 Any
args_( getValueByName( rName
+ "/arguments" ) );
296 if (args_
.hasValue() && !(args_
>>= 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 );
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(
334 catch (const RuntimeException
&)
338 catch (const Exception
& exc
)
342 "exception occurred raising singleton \"" << rName
<< "\": "
346 SAL_WARN_IF(!xInstance
.is(),
347 "cppuhelper", "no service object raising singleton " << rName
);
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
;
364 if (ret
!= xInstance
) {
365 try_dispose( xInstance
);
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
);
389 Reference
< lang::XMultiComponentFactory
> ComponentContext::getServiceManager()
393 throw DeploymentException(
394 "null component context service manager",
395 static_cast<OWeakObject
*>(this) );
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
)
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
422 !iPos
->first
.startsWith( SMGR_SINGLETON
))
424 if (pEntry
->lateInit
)
427 MutexGuard
guard( m_mutex
);
428 if (pEntry
->lateInit
)
430 pEntry
->value
.clear(); // release factory
431 pEntry
->lateInit
= false;
436 Reference
< lang::XComponent
> xComp
;
437 pEntry
->value
>>= xComp
;
440 if ( iPos
->first
== TDMGR_SINGLETON
)
444 else if ( iPos
->first
== AC_SINGLETON
)
448 else // dispose immediately
456 // dispose service manager
457 try_dispose( m_xSMgr
);
461 // dispose tdmgr; revokes callback from cppu runtime
462 try_dispose( xTDMgr
);
464 iPos
= m_map
.begin();
465 for ( ; iPos
!= iEnd
; ++iPos
)
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
;
474 uno_getRegisteredEnvironments(
475 &envs
, &envCount
, &rtl_allocateMemory
, OUString("java").pData
);
476 assert(envCount
>= 0);
477 assert(envCount
== 0 || envs
!= nullptr);
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
)
506 m_map
[ rEntry
.name
] = new ContextEntry( Any(), true );
508 m_map
[ rEntry
.name
+ "/service" ] = new ContextEntry( rEntry
.value
, false );
509 // initial-arguments are provided as optional context entry
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() );
524 osl_atomic_increment( &m_refCount
);
527 // create new smgr based on delegate's one
529 xMgr
->createInstanceWithContext(
530 "com.sun.star.comp.stoc.OServiceManagerWrapper", xDelegate
),
532 // patch DefaultContext property of new one
533 Reference
< beans::XPropertySet
> xProps( m_xSMgr
, UNO_QUERY
);
534 OSL_ASSERT( xProps
.is() );
537 Reference
< XComponentContext
> xThis( this );
538 xProps
->setPropertyValue( "DefaultContext", Any( xThis
) );
543 osl_atomic_decrement( &m_refCount
);
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
;
568 ComponentContext
* p
= new ComponentContext( pEntries
, nEntries
, xDelegate
);
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
);
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(),
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: */