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