1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_cppuhelper.hxx"
26 
27 #ifdef DIAG
28 #define CONTEXT_DIAG
29 #endif
30 
31 #if OSL_DEBUG_LEVEL > 0
32 #include <stdio.h>
33 #endif
34 
35 #include <vector>
36 #include <hash_map>
37 #ifdef CONTEXT_DIAG
38 #include <map>
39 #endif
40 
41 #include <osl/diagnose.h>
42 #include <osl/mutex.hxx>
43 
44 #include <rtl/ustrbuf.hxx>
45 
46 #include <uno/mapping.hxx>
47 
48 #include <cppuhelper/implbase1.hxx>
49 #include <cppuhelper/compbase2.hxx>
50 #include <cppuhelper/component_context.hxx>
51 #include <cppuhelper/exc_hlp.hxx>
52 
53 #include <com/sun/star/container/XNameContainer.hpp>
54 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
55 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
56 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
57 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
58 #include <com/sun/star/lang/XComponent.hpp>
59 #include <com/sun/star/beans/XPropertySet.hpp>
60 #include "com/sun/star/uno/RuntimeException.hpp"
61 
62 #include <hash_map>
63 #include <memory>
64 
65 #define SMGR_SINGLETON "/singletons/com.sun.star.lang.theServiceManager"
66 #define TDMGR_SINGLETON "/singletons/com.sun.star.reflection.theTypeDescriptionManager"
67 #define AC_SINGLETON "/singletons/com.sun.star.security.theAccessController"
68 #define AC_POLICY "/singletons/com.sun.star.security.thePolicy"
69 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
70 
71 
72 using namespace ::osl;
73 using namespace ::rtl;
74 using namespace ::com::sun::star::uno;
75 using namespace ::com::sun::star;
76 
77 namespace cppu
78 {
79 
80 #ifdef CONTEXT_DIAG
81 //--------------------------------------------------------------------------------------------------
82 static OUString val2str( void const * pVal, typelib_TypeDescriptionReference * pTypeRef )
83 {
84 	OSL_ASSERT( pVal );
85 	if (pTypeRef->eTypeClass == typelib_TypeClass_VOID)
86 		return OUSTR("void");
87 
88 	OUStringBuffer buf( 64 );
89 	buf.append( (sal_Unicode)'(' );
90 	buf.append( pTypeRef->pTypeName );
91 	buf.append( (sal_Unicode)')' );
92 
93 	switch (pTypeRef->eTypeClass)
94 	{
95 	case typelib_TypeClass_INTERFACE:
96 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
97 		buf.append( (sal_Int64)*(void **)pVal, 16 );
98 		break;
99 	case typelib_TypeClass_STRUCT:
100 	case typelib_TypeClass_EXCEPTION:
101 	{
102 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
103 		typelib_TypeDescription * pTypeDescr = 0;
104 		::typelib_typedescriptionreference_getDescription( &pTypeDescr, pTypeRef );
105 		OSL_ASSERT( pTypeDescr );
106 		if (! pTypeDescr->bComplete)
107 			::typelib_typedescription_complete( &pTypeDescr );
108 
109 		typelib_CompoundTypeDescription * pCompType = (typelib_CompoundTypeDescription *)pTypeDescr;
110 		sal_Int32 nDescr = pCompType->nMembers;
111 
112 		if (pCompType->pBaseTypeDescription)
113 		{
114 			buf.append( val2str( pVal, ((typelib_TypeDescription *)pCompType->pBaseTypeDescription)->pWeakRef ) );
115 			if (nDescr)
116 				buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
117 		}
118 
119 		typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs;
120 		sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets;
121 		rtl_uString ** ppMemberNames = pCompType->ppMemberNames;
122 
123 		for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos )
124 		{
125 			buf.append( ppMemberNames[ nPos ] );
126 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" = ") );
127 			typelib_TypeDescription * pMemberType = 0;
128 			TYPELIB_DANGER_GET( &pMemberType, ppTypeRefs[ nPos ] );
129 			buf.append( val2str( (char *)pVal + pMemberOffsets[ nPos ], pMemberType->pWeakRef ) );
130 			TYPELIB_DANGER_RELEASE( pMemberType );
131 			if (nPos < (nDescr -1))
132 				buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
133 		}
134 
135 		::typelib_typedescription_release( pTypeDescr );
136 
137 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
138 		break;
139 	}
140 	case typelib_TypeClass_SEQUENCE:
141 	{
142 		typelib_TypeDescription * pTypeDescr = 0;
143 		TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
144 
145 		uno_Sequence * pSequence = *(uno_Sequence **)pVal;
146 		typelib_TypeDescription * pElementTypeDescr = 0;
147 		TYPELIB_DANGER_GET( &pElementTypeDescr, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType );
148 
149 		sal_Int32 nElementSize = pElementTypeDescr->nSize;
150 		sal_Int32 nElements	   = pSequence->nElements;
151 
152 		if (nElements)
153 		{
154 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
155 			char * pElements = pSequence->elements;
156 			for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
157 			{
158 				buf.append( val2str( pElements + (nElementSize * nPos), pElementTypeDescr->pWeakRef ) );
159 				if (nPos < (nElements -1))
160 					buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") );
161 			}
162 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
163 		}
164 		else
165 		{
166 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{}") );
167 		}
168 		TYPELIB_DANGER_RELEASE( pElementTypeDescr );
169 		TYPELIB_DANGER_RELEASE( pTypeDescr );
170 		break;
171 	}
172 	case typelib_TypeClass_ANY:
173 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("{ ") );
174 		buf.append( val2str( ((uno_Any *)pVal)->pData,
175 							 ((uno_Any *)pVal)->pType ) );
176 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" }") );
177 		break;
178 	case typelib_TypeClass_TYPE:
179 		buf.append( (*(typelib_TypeDescriptionReference **)pVal)->pTypeName );
180 		break;
181 	case typelib_TypeClass_STRING:
182 		buf.append( (sal_Unicode)'\"' );
183 		buf.append( *(rtl_uString **)pVal );
184 		buf.append( (sal_Unicode)'\"' );
185 		break;
186 	case typelib_TypeClass_ENUM:
187 	{
188 		typelib_TypeDescription * pTypeDescr = 0;
189 		::typelib_typedescriptionreference_getDescription( &pTypeDescr, pTypeRef );
190 		OSL_ASSERT( pTypeDescr );
191 		if (! pTypeDescr->bComplete)
192 			::typelib_typedescription_complete( &pTypeDescr );
193 
194 		sal_Int32 * pValues = ((typelib_EnumTypeDescription *)pTypeDescr)->pEnumValues;
195 		sal_Int32 nPos = ((typelib_EnumTypeDescription *)pTypeDescr)->nEnumValues;
196 		while (nPos--)
197 		{
198 			if (pValues[ nPos ] == *(sal_Int32 *)pVal)
199 				break;
200 		}
201 		if (nPos >= 0)
202 			buf.append( ((typelib_EnumTypeDescription *)pTypeDescr)->ppEnumNames[ nPos ] );
203 		else
204 			buf.append( (sal_Unicode)'?' );
205 
206 		::typelib_typedescription_release( pTypeDescr );
207 		break;
208 	}
209 	case typelib_TypeClass_BOOLEAN:
210 		if (*(sal_Bool *)pVal)
211 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("true") );
212 		else
213 			buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("false") );
214 		break;
215 	case typelib_TypeClass_CHAR:
216 		buf.append( (sal_Unicode)'\'' );
217 		buf.append( *(sal_Unicode *)pVal );
218 		buf.append( (sal_Unicode)'\'' );
219 		break;
220 	case typelib_TypeClass_FLOAT:
221 		buf.append( *(float *)pVal );
222 		break;
223 	case typelib_TypeClass_DOUBLE:
224 		buf.append( *(double *)pVal );
225 		break;
226 	case typelib_TypeClass_BYTE:
227 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
228 		buf.append( (sal_Int32)*(sal_Int8 *)pVal, 16 );
229 		break;
230 	case typelib_TypeClass_SHORT:
231 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
232 		buf.append( (sal_Int32)*(sal_Int16 *)pVal, 16 );
233 		break;
234 	case typelib_TypeClass_UNSIGNED_SHORT:
235 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
236 		buf.append( (sal_Int32)*(sal_uInt16 *)pVal, 16 );
237 		break;
238 	case typelib_TypeClass_LONG:
239 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
240 		buf.append( *(sal_Int32 *)pVal, 16 );
241 		break;
242 	case typelib_TypeClass_UNSIGNED_LONG:
243 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
244 		buf.append( (sal_Int64)*(sal_uInt32 *)pVal, 16 );
245 		break;
246 	case typelib_TypeClass_HYPER:
247 	case typelib_TypeClass_UNSIGNED_HYPER:
248 		buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("0x") );
249 #if defined(GCC) && defined(SPARC)
250 		{
251 			sal_Int64 aVal;
252 			*(sal_Int32 *)&aVal = *(sal_Int32 *)pVal;
253 			*((sal_Int32 *)&aVal +1)= *((sal_Int32 *)pVal +1);
254 			buf.append( aVal, 16 );
255 		}
256 #else
257 		buf.append( *(sal_Int64 *)pVal, 16 );
258 #endif
259 		break;
260 	default:
261 		buf.append( (sal_Unicode)'?' );
262 	}
263 
264 	return buf.makeStringAndClear();
265 }
266 //--------------------------------------------------------------------------------------------------
267 static void dumpEntry( OUString const & key, Any const & value )
268 {
269     OUString val( val2str( value.getValue(), value.getValueTypeRef() ) );
270     OString key_str( OUStringToOString( key, RTL_TEXTENCODING_ASCII_US ) );
271     OString val_str( OUStringToOString( val, RTL_TEXTENCODING_ASCII_US ) );
272     ::fprintf( stderr, "| %s = %s\n", key_str.getStr(), val_str.getStr() );
273 }
274 #endif
275 //--------------------------------------------------------------------------------------------------
276 static inline void try_dispose( Reference< XInterface > const & xInstance )
277     SAL_THROW( (RuntimeException) )
278 {
279     Reference< lang::XComponent > xComp( xInstance, UNO_QUERY );
280     if (xComp.is())
281     {
282         xComp->dispose();
283     }
284 }
285 //--------------------------------------------------------------------------------------------------
286 static inline void try_dispose( Reference< lang::XComponent > const & xComp )
287     SAL_THROW( (RuntimeException) )
288 {
289     if (xComp.is())
290     {
291         xComp->dispose();
292     }
293 }
294 
295 //==================================================================================================
296 
297 class DisposingForwarder
298     : public WeakImplHelper1< lang::XEventListener >
299 {
300     Reference< lang::XComponent > m_xTarget;
301 
302     inline DisposingForwarder( Reference< lang::XComponent > const & xTarget )
303         SAL_THROW( () )
304         : m_xTarget( xTarget )
305         { OSL_ASSERT( m_xTarget.is() ); }
306 public:
307     // listens at source for disposing, then disposes target
308     static inline void listen(
309         Reference< lang::XComponent > const & xSource,
310         Reference< lang::XComponent > const & xTarget )
311         SAL_THROW( (RuntimeException) );
312 
313     virtual void SAL_CALL disposing( lang::EventObject const & rSource )
314         throw (RuntimeException);
315 };
316 //__________________________________________________________________________________________________
317 inline void DisposingForwarder::listen(
318     Reference< lang::XComponent > const & xSource,
319     Reference< lang::XComponent > const & xTarget )
320     SAL_THROW( (RuntimeException) )
321 {
322     if (xSource.is())
323     {
324         xSource->addEventListener( new DisposingForwarder( xTarget ) );
325     }
326 }
327 //__________________________________________________________________________________________________
328 void DisposingForwarder::disposing( lang::EventObject const & )
329     throw (RuntimeException)
330 {
331     m_xTarget->dispose();
332     m_xTarget.clear();
333 }
334 
335 //==================================================================================================
336 struct MutexHolder
337 {
338 protected:
339     Mutex m_mutex;
340 };
341 //==================================================================================================
342 
343 class ComponentContext
344     : private MutexHolder
345     , public WeakComponentImplHelper2< XComponentContext,
346                                        container::XNameContainer >
347 {
348 protected:
349     Reference< XComponentContext > m_xDelegate;
350 
351     struct ContextEntry
352     {
353         Any value;
354         bool lateInit;
355 
356         inline ContextEntry( Any const & value_, bool lateInit_ )
357             : value( value_ )
358             , lateInit( lateInit_ )
359             {}
360     };
361     typedef ::std::hash_map< OUString, ContextEntry * , OUStringHash > t_map;
362     t_map m_map;
363 
364     Reference< lang::XMultiComponentFactory > m_xSMgr;
365 
366 protected:
367     Any lookupMap( OUString const & rName )
368         SAL_THROW( (RuntimeException) );
369 
370 	virtual void SAL_CALL disposing();
371 public:
372     ComponentContext(
373         ContextEntry_Init const * pEntries, sal_Int32 nEntries,
374         Reference< XComponentContext > const & xDelegate );
375     virtual ~ComponentContext()
376         SAL_THROW( () );
377 
378     // XComponentContext
379     virtual Any SAL_CALL getValueByName( OUString const & rName )
380         throw (RuntimeException);
381     virtual Reference<lang::XMultiComponentFactory> SAL_CALL getServiceManager()
382         throw (RuntimeException);
383 
384     // XNameContainer
385     virtual void SAL_CALL insertByName(
386         OUString const & name, Any const & element )
387         throw (lang::IllegalArgumentException, container::ElementExistException,
388                lang::WrappedTargetException, RuntimeException);
389     virtual void SAL_CALL removeByName( OUString const & name )
390         throw (container::NoSuchElementException,
391                lang::WrappedTargetException, RuntimeException);
392     // XNameReplace
393     virtual void SAL_CALL replaceByName(
394         OUString const & name, Any const & element )
395         throw (lang::IllegalArgumentException,container::NoSuchElementException,
396                lang::WrappedTargetException, RuntimeException);
397     // XNameAccess
398     virtual Any SAL_CALL getByName( OUString const & name )
399         throw (container::NoSuchElementException,
400                lang::WrappedTargetException, RuntimeException);
401     virtual Sequence<OUString> SAL_CALL getElementNames()
402         throw (RuntimeException);
403     virtual sal_Bool SAL_CALL hasByName( OUString const & name )
404         throw (RuntimeException);
405     // XElementAccess
406     virtual Type SAL_CALL getElementType() throw (RuntimeException);
407     virtual sal_Bool SAL_CALL hasElements() throw (RuntimeException);
408 };
409 
410 // XNameContainer
411 //______________________________________________________________________________
412 void ComponentContext::insertByName(
413     OUString const & name, Any const & element )
414     throw (lang::IllegalArgumentException, container::ElementExistException,
415            lang::WrappedTargetException, RuntimeException)
416 {
417     t_map::mapped_type entry(
418         new ContextEntry(
419             element,
420             /* lateInit_: */
421             name.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("/singletons/") ) &&
422             !element.hasValue() ) );
423     MutexGuard guard( m_mutex );
424     ::std::pair<t_map::iterator, bool> insertion( m_map.insert(
425         t_map::value_type( name, entry ) ) );
426     if (! insertion.second)
427         throw container::ElementExistException(
428             OUSTR("element already exists: ") + name,
429             static_cast<OWeakObject *>(this) );
430 }
431 
432 //______________________________________________________________________________
433 void ComponentContext::removeByName( OUString const & name )
434         throw (container::NoSuchElementException,
435                lang::WrappedTargetException, RuntimeException)
436 {
437     MutexGuard guard( m_mutex );
438     t_map::iterator iFind( m_map.find( name ) );
439     if (iFind == m_map.end())
440         throw container::NoSuchElementException(
441             OUSTR("no such element: ") + name,
442             static_cast<OWeakObject *>(this) );
443 
444     delete iFind->second;
445     m_map.erase(iFind);
446 }
447 
448 // XNameReplace
449 //______________________________________________________________________________
450 void ComponentContext::replaceByName(
451     OUString const & name, Any const & element )
452     throw (lang::IllegalArgumentException,container::NoSuchElementException,
453            lang::WrappedTargetException, RuntimeException)
454 {
455     MutexGuard guard( m_mutex );
456     t_map::const_iterator const iFind( m_map.find( name ) );
457     if (iFind == m_map.end())
458         throw container::NoSuchElementException(
459             OUSTR("no such element: ") + name,
460             static_cast<OWeakObject *>(this) );
461     if (name.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("/singletons/") ) &&
462         !element.hasValue())
463     {
464         iFind->second->value.clear();
465         iFind->second->lateInit = true;
466     }
467     else
468     {
469         iFind->second->value = element;
470         iFind->second->lateInit = false;
471     }
472 }
473 
474 // XNameAccess
475 //______________________________________________________________________________
476 Any ComponentContext::getByName( OUString const & name )
477     throw (container::NoSuchElementException,
478            lang::WrappedTargetException, RuntimeException)
479 {
480     return getValueByName( name );
481 }
482 
483 //______________________________________________________________________________
484 Sequence<OUString> ComponentContext::getElementNames()
485     throw (RuntimeException)
486 {
487     MutexGuard guard( m_mutex );
488     Sequence<OUString> ret( m_map.size() );
489     OUString * pret = ret.getArray();
490     sal_Int32 pos = 0;
491     t_map::const_iterator iPos( m_map.begin() );
492     t_map::const_iterator const iEnd( m_map.end() );
493     for ( ; iPos != iEnd; ++iPos )
494         pret[pos++] = iPos->first;
495     return ret;
496 }
497 
498 //______________________________________________________________________________
499 sal_Bool ComponentContext::hasByName( OUString const & name )
500     throw (RuntimeException)
501 {
502     MutexGuard guard( m_mutex );
503     return m_map.find( name ) != m_map.end();
504 }
505 
506 // XElementAccess
507 //______________________________________________________________________________
508 Type ComponentContext::getElementType() throw (RuntimeException)
509 {
510     return ::getVoidCppuType();
511 }
512 
513 //______________________________________________________________________________
514 sal_Bool ComponentContext::hasElements() throw (RuntimeException)
515 {
516     MutexGuard guard( m_mutex );
517     return ! m_map.empty();
518 }
519 
520 //__________________________________________________________________________________________________
521 Any ComponentContext::lookupMap( OUString const & rName )
522     SAL_THROW( (RuntimeException) )
523 {
524 #ifdef CONTEXT_DIAG
525     if (rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("dump_maps") ))
526     {
527         ::fprintf( stderr, ">>> dumping out ComponentContext %p m_map:\n", this );
528         typedef ::std::map< OUString, ContextEntry * > t_sorted; // sorted map
529         t_sorted sorted;
530         for ( t_map::const_iterator iPos( m_map.begin() ); iPos != m_map.end(); ++iPos )
531         {
532             sorted[ iPos->first ] = iPos->second;
533         }
534         {
535         for ( t_sorted::const_iterator iPos( sorted.begin() ); iPos != sorted.end(); ++iPos )
536         {
537             dumpEntry( iPos->first, iPos->second->value );
538         }
539         }
540         return Any();
541     }
542 #endif
543 
544     ResettableMutexGuard guard( m_mutex );
545     t_map::const_iterator iFind( m_map.find( rName ) );
546     if (iFind == m_map.end())
547         return Any();
548 
549     t_map::mapped_type pEntry = iFind->second;
550     if (! pEntry->lateInit)
551         return pEntry->value;
552 
553     // late init singleton entry
554     Reference< XInterface > xInstance;
555     guard.clear();
556 
557     try
558     {
559         Any usesService( getValueByName( rName + OUSTR("/service") ) );
560         Any args_( getValueByName( rName + OUSTR("/arguments") ) );
561         Sequence<Any> args;
562         if (args_.hasValue() && !(args_ >>= args))
563         {
564             args.realloc( 1 );
565             args[ 0 ] = args_;
566         }
567 
568         Reference< lang::XSingleComponentFactory > xFac;
569         if (usesService >>= xFac) // try via factory
570         {
571             xInstance = args.getLength()
572                 ? xFac->createInstanceWithArgumentsAndContext( args, this )
573                 : xFac->createInstanceWithContext( this );
574         }
575         else
576         {
577             Reference< lang::XSingleServiceFactory > xFac2;
578             if (usesService >>= xFac2)
579             {
580                 // try via old XSingleServiceFactory
581 #if OSL_DEBUG_LEVEL > 0
582                 ::fprintf(
583                     stderr,
584                     "### omitting context for service instanciation!\n" );
585 #endif
586                 xInstance = args.getLength()
587                     ? xFac2->createInstanceWithArguments( args )
588                     : xFac2->createInstance();
589             }
590             else if (m_xSMgr.is()) // optionally service name
591             {
592                 OUString serviceName;
593                 if ((usesService >>= serviceName) &&
594                     serviceName.getLength())
595                 {
596                     xInstance = args.getLength()
597                         ? m_xSMgr->createInstanceWithArgumentsAndContext(
598                             serviceName, args, this )
599                         : m_xSMgr->createInstanceWithContext(
600                             serviceName, this );
601                 }
602             }
603         }
604     }
605     catch (RuntimeException &)
606     {
607         throw;
608     }
609     catch (Exception & exc) // rethrow as WrappedTargetRuntimeException
610     {
611         Any caught( getCaughtException() );
612         OUStringBuffer buf;
613         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
614                              "exception occured raising singleton \"") );
615         buf.append( rName );
616         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\": ") );
617         buf.append( exc.Message );
618         throw lang::WrappedTargetRuntimeException(
619             buf.makeStringAndClear(), static_cast<OWeakObject *>(this),caught );
620     }
621 
622     if (! xInstance.is())
623     {
624         throw RuntimeException(
625             OUSTR("no service object raising singleton ") + rName,
626             static_cast<OWeakObject *>(this) );
627     }
628 
629     Any ret;
630     guard.reset();
631     iFind = m_map.find( rName );
632     if (iFind != m_map.end())
633     {
634         pEntry = iFind->second;
635         if (pEntry->lateInit)
636         {
637             pEntry->value <<= xInstance;
638             pEntry->lateInit = false;
639             return pEntry->value;
640         }
641         else
642             ret = pEntry->value;
643     }
644     guard.clear();
645     try_dispose( xInstance );
646     return ret;
647 }
648 
649 //__________________________________________________________________________________________________
650 Any ComponentContext::getValueByName( OUString const & rName )
651     throw (RuntimeException)
652 {
653     // to determine the root context:
654     if (rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("_root") ))
655     {
656         if (m_xDelegate.is())
657             return m_xDelegate->getValueByName( rName );
658         else
659             return makeAny( Reference<XComponentContext>(this) );
660     }
661 
662     Any ret( lookupMap( rName ) );
663     if (!ret.hasValue() && m_xDelegate.is())
664     {
665         return m_xDelegate->getValueByName( rName );
666     }
667     return ret;
668 }
669 //__________________________________________________________________________________________________
670 Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager()
671     throw (RuntimeException)
672 {
673     return m_xSMgr;
674 }
675 //__________________________________________________________________________________________________
676 ComponentContext::~ComponentContext()
677     SAL_THROW( () )
678 {
679 #ifdef CONTEXT_DIAG
680     ::fprintf( stderr, "> destructed context %p\n", this );
681 #endif
682     t_map::const_iterator iPos( m_map.begin() );
683     t_map::const_iterator const iEnd( m_map.end() );
684     for ( ; iPos != iEnd; ++iPos )
685         delete iPos->second;
686     m_map.clear();
687 }
688 //__________________________________________________________________________________________________
689 void ComponentContext::disposing()
690 {
691 #ifdef CONTEXT_DIAG
692     ::fprintf( stderr, "> disposing context %p\n", this );
693 #endif
694 
695     Reference< lang::XComponent > xTDMgr, xAC, xPolicy; // to be disposed separately
696 
697     // dispose all context objects
698     t_map::const_iterator iPos( m_map.begin() );
699     t_map::const_iterator const iEnd( m_map.end() );
700     for ( ; iPos != iEnd; ++iPos )
701     {
702         t_map::mapped_type pEntry = iPos->second;
703 
704         // service manager disposed separately
705         if (!m_xSMgr.is() ||
706             !iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_SINGLETON) ))
707         {
708             if (pEntry->lateInit)
709             {
710                 // late init
711                 MutexGuard guard( m_mutex );
712                 if (pEntry->lateInit)
713                 {
714                     pEntry->value.clear(); // release factory
715                     pEntry->lateInit = false;
716                     continue;
717                 }
718             }
719 
720             Reference< lang::XComponent > xComp;
721             pEntry->value >>= xComp;
722             if (xComp.is())
723             {
724                 if (iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(TDMGR_SINGLETON) ))
725                 {
726                     xTDMgr = xComp;
727                 }
728                 else if (iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(AC_SINGLETON) ))
729                 {
730                     xAC = xComp;
731                 }
732                 else if (iPos->first.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(AC_POLICY) ))
733                 {
734                     xPolicy = xComp;
735                 }
736                 else // dispose immediately
737                 {
738                     xComp->dispose();
739                 }
740             }
741         }
742     }
743 
744     // dispose service manager
745     try_dispose( m_xSMgr );
746     m_xSMgr.clear();
747     // dispose ac
748     try_dispose( xAC );
749     // dispose policy
750     try_dispose( xPolicy );
751     // dispose tdmgr; revokes callback from cppu runtime
752     try_dispose( xTDMgr );
753 
754     iPos = m_map.begin();
755     for ( ; iPos != iEnd; ++iPos )
756         delete iPos->second;
757     m_map.clear();
758 }
759 //__________________________________________________________________________________________________
760 ComponentContext::ComponentContext(
761     ContextEntry_Init const * pEntries, sal_Int32 nEntries,
762     Reference< XComponentContext > const & xDelegate )
763     : WeakComponentImplHelper2< XComponentContext, container::XNameContainer >(
764         m_mutex ),
765       m_xDelegate( xDelegate )
766 {
767     for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos )
768     {
769         ContextEntry_Init const & rEntry = pEntries[ nPos ];
770 
771         if (rEntry.name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SMGR_SINGLETON) ))
772         {
773             rEntry.value >>= m_xSMgr;
774         }
775 
776         if (rEntry.bLateInitService)
777         {
778             // singleton entry
779             m_map[ rEntry.name ] = new ContextEntry( Any(), true );
780             // /service
781             m_map[ rEntry.name + OUSTR("/service") ] = new ContextEntry( rEntry.value, false );
782             // /initial-arguments are provided as optional context entry
783         }
784         else
785         {
786             // only value, no late init factory nor string
787             m_map[ rEntry.name ] = new ContextEntry( rEntry.value, false );
788         }
789     }
790 
791     if (!m_xSMgr.is() && m_xDelegate.is())
792     {
793         // wrap delegate's smgr XPropertySet into new smgr
794         Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() );
795         if (xMgr.is())
796         {
797             osl_incrementInterlockedCount( &m_refCount );
798             try
799             {
800                 // create new smgr based on delegate's one
801                 m_xSMgr.set(
802                     xMgr->createInstanceWithContext(
803                         OUSTR("com.sun.star.comp.stoc.OServiceManagerWrapper"), xDelegate ),
804                     UNO_QUERY );
805                 // patch DefaultContext property of new one
806                 Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY );
807                 OSL_ASSERT( xProps.is() );
808                 if (xProps.is())
809                 {
810                     Reference< XComponentContext > xThis( this );
811                     xProps->setPropertyValue( OUSTR("DefaultContext"), makeAny( xThis ) );
812                 }
813             }
814             catch (...)
815             {
816                 osl_decrementInterlockedCount( &m_refCount );
817                 throw;
818             }
819             osl_decrementInterlockedCount( &m_refCount );
820             OSL_ASSERT( m_xSMgr.is() );
821         }
822     }
823 }
824 
825 
826 //##################################################################################################
827 extern "C" { static void s_createComponentContext_v(va_list * pParam)
828 {
829     ContextEntry_Init const  * pEntries     = va_arg(*pParam, ContextEntry_Init const *);
830 	sal_Int32                  nEntries     = va_arg(*pParam, sal_Int32);
831 	XComponentContext        * pDelegatee   = va_arg(*pParam, XComponentContext *);
832 	void                    ** ppContext    = va_arg(*pParam, void **);
833 	uno::Mapping             * pTarget2curr = va_arg(*pParam, uno::Mapping *);
834 
835 	Reference<XComponentContext> xDelegate(pDelegatee, SAL_NO_ACQUIRE);
836 	Reference<XComponentContext> xContext;
837 
838     if (nEntries > 0)
839     {
840         try
841         {
842 			ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate );
843             xContext.set(p);
844             // listen delegate for disposing, to dispose this (wrapping) context first.
845             DisposingForwarder::listen( Reference< lang::XComponent >::query( xDelegate ), p );
846         }
847         catch (Exception & exc)
848         {
849             (void) exc; // avoid warning about unused variable
850             OSL_ENSURE( 0, OUStringToOString(
851                             exc.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
852 			xContext.clear();
853         }
854     }
855     else
856     {
857         xContext = xDelegate;
858     }
859 
860 	delete[] pEntries;
861 
862 	*ppContext = pTarget2curr->mapInterface(xContext.get(), ::getCppuType(&xContext));
863 }}
864 
865 Reference< XComponentContext > SAL_CALL createComponentContext(
866     ContextEntry_Init const * pEntries, sal_Int32 nEntries,
867     Reference< XComponentContext > const & xDelegate )
868     SAL_THROW( () )
869 {
870 	uno::Environment curr_env(Environment::getCurrent());
871 	uno::Environment source_env(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(CPPU_STRINGIFY(CPPU_ENV))));
872 
873 	uno::Mapping curr2source(curr_env, source_env);
874 	uno::Mapping source2curr(source_env, curr_env);
875 
876 	ContextEntry_Init * mapped_entries = new ContextEntry_Init[nEntries];
877 	for (sal_Int32 nPos = 0; nPos < nEntries; ++ nPos)
878 	{
879 		mapped_entries[nPos].bLateInitService = pEntries[nPos].bLateInitService;
880 		mapped_entries[nPos].name             = pEntries[nPos].name;
881 
882 		uno_type_any_constructAndConvert(&mapped_entries[nPos].value,
883 										 const_cast<void *>(pEntries[nPos].value.getValue()),
884 										 pEntries[nPos].value.getValueTypeRef(),
885 										 curr2source.get());
886 	}
887 
888 	void * mapped_delegate = curr2source.mapInterface(xDelegate.get(), ::getCppuType(&xDelegate));
889 	XComponentContext * pXComponentContext = NULL;
890 	source_env.invoke(s_createComponentContext_v, mapped_entries, nEntries, mapped_delegate, &pXComponentContext, &source2curr);
891 
892 	return Reference<XComponentContext>(pXComponentContext, SAL_NO_ACQUIRE);
893 }
894 
895 }
896