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_stoc.hxx"
30 #include <cppuhelper/queryinterface.hxx>
31 #ifndef _CPPUHELPER_IMPLEMENTATIONENTRY_HXX_
32 #include <cppuhelper/implementationentry.hxx>
33 #endif
34 
35 #include <com/sun/star/lang/XComponent.hpp>
36 #include <com/sun/star/reflection/XTypeDescription.hpp>
37 #include "com/sun/star/uno/RuntimeException.hpp"
38 
39 using namespace com::sun::star;
40 using namespace com::sun::star::lang;
41 using namespace com::sun::star::registry;
42 using namespace cppu;
43 using namespace osl;
44 using namespace rtl;
45 
46 #include "base.hxx"
47 
48 
49 namespace stoc_corefl
50 {
51 
52 static const sal_Int32 CACHE_SIZE = 256;
53 
54 #define SERVICENAME "com.sun.star.reflection.CoreReflection"
55 #define IMPLNAME	"com.sun.star.comp.stoc.CoreReflection"
56 
57 // can be static, as every client of the core reflection keeps a reference to the
58 // core reflection, so refcounting can be done here.
59 static rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT;
60 
61 static Sequence< OUString > core_getSupportedServiceNames()
62 {
63 	static Sequence < OUString > *pNames = 0;
64 	if( ! pNames )
65 	{
66 		MutexGuard guard( Mutex::getGlobalMutex() );
67 		if( !pNames )
68 		{
69 			static Sequence< OUString > seqNames(1);
70 			seqNames.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(SERVICENAME) );
71 			pNames = &seqNames;
72 		}
73 	}
74 	return *pNames;
75 }
76 
77 static OUString core_getImplementationName()
78 {
79 	static OUString *pImplName = 0;
80 	if( ! pImplName )
81 	{
82 		MutexGuard guard( Mutex::getGlobalMutex() );
83 		if( ! pImplName )
84 		{
85 			static OUString implName( RTL_CONSTASCII_USTRINGPARAM( IMPLNAME ) );
86 			pImplName = &implName;
87 		}
88 	}
89 	return *pImplName;
90 }
91 //__________________________________________________________________________________________________
92 IdlReflectionServiceImpl::IdlReflectionServiceImpl(
93     const Reference< XComponentContext > & xContext )
94 	: OComponentHelper( _aComponentMutex )
95 	, _xMgr( xContext->getServiceManager(), UNO_QUERY )
96 	, _aElements( CACHE_SIZE )
97 {
98 	g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
99     xContext->getValueByName( OUString( RTL_CONSTASCII_USTRINGPARAM(
100         "/singletons/com.sun.star.reflection.theTypeDescriptionManager") ) ) >>= _xTDMgr;
101 	OSL_ENSURE( _xTDMgr.is(), "### cannot get singleton \"TypeDescriptionManager\" from context!" );
102 }
103 //__________________________________________________________________________________________________
104 IdlReflectionServiceImpl::~IdlReflectionServiceImpl()
105 {
106 	TRACE( "> IdlReflectionServiceImpl dtor <\n" );
107 	g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
108 }
109 
110 // XInterface
111 //__________________________________________________________________________________________________
112 Any IdlReflectionServiceImpl::queryInterface( const Type & rType )
113 	throw(::com::sun::star::uno::RuntimeException)
114 {
115 	Any aRet( ::cppu::queryInterface(
116 		rType,
117 		static_cast< XIdlReflection * >( this ),
118 		static_cast< XHierarchicalNameAccess * >( this ),
119 		static_cast< XServiceInfo * >( this ) ) );
120 
121 	return (aRet.hasValue() ? aRet : OComponentHelper::queryInterface( rType ));
122 }
123 //__________________________________________________________________________________________________
124 void IdlReflectionServiceImpl::acquire() throw()
125 {
126 	OComponentHelper::acquire();
127 }
128 //__________________________________________________________________________________________________
129 void IdlReflectionServiceImpl::release() throw()
130 {
131 	OComponentHelper::release();
132 }
133 
134 // XTypeProvider
135 //__________________________________________________________________________________________________
136 Sequence< Type > IdlReflectionServiceImpl::getTypes()
137 	throw (::com::sun::star::uno::RuntimeException)
138 {
139 	static OTypeCollection * s_pTypes = 0;
140 	if (! s_pTypes)
141 	{
142 		MutexGuard aGuard( _aComponentMutex );
143 		if (! s_pTypes)
144 		{
145 			static OTypeCollection s_aTypes(
146 				::getCppuType( (const Reference< XIdlReflection > *)0 ),
147 				::getCppuType( (const Reference< XHierarchicalNameAccess > *)0 ),
148 				::getCppuType( (const Reference< XServiceInfo > *)0 ),
149 				OComponentHelper::getTypes() );
150 			s_pTypes = &s_aTypes;
151 		}
152 	}
153 	return s_pTypes->getTypes();
154 }
155 //__________________________________________________________________________________________________
156 Sequence< sal_Int8 > IdlReflectionServiceImpl::getImplementationId()
157 	throw (::com::sun::star::uno::RuntimeException)
158 {
159 	static OImplementationId * s_pId = 0;
160 	if (! s_pId)
161 	{
162 		MutexGuard aGuard( _aComponentMutex );
163 		if (! s_pId)
164 		{
165 			static OImplementationId s_aId;
166 			s_pId = &s_aId;
167 		}
168 	}
169 	return s_pId->getImplementationId();
170 }
171 
172 // XComponent
173 //__________________________________________________________________________________________________
174 void IdlReflectionServiceImpl::dispose()
175 	throw(::com::sun::star::uno::RuntimeException)
176 {
177 	TRACE( "> disposing corereflection... <" );
178 	OComponentHelper::dispose();
179 
180 	MutexGuard aGuard( _aComponentMutex );
181 	_aElements.clear();
182 #ifdef TEST_LIST_CLASSES
183 	OSL_ENSURE( g_aClassNames.size() == 0, "### idl classes still alive!" );
184 	ClassNameList::const_iterator iPos( g_aClassNames.begin() );
185 	while (iPos != g_aClassNames.end())
186 	{
187 		OUString aName( *iPos );
188 		++iPos;
189 	}
190 #endif
191 }
192 
193 // XServiceInfo
194 //__________________________________________________________________________________________________
195 OUString IdlReflectionServiceImpl::getImplementationName()
196 	throw(::com::sun::star::uno::RuntimeException)
197 {
198 	return core_getImplementationName();
199 }
200 //__________________________________________________________________________________________________
201 sal_Bool IdlReflectionServiceImpl::supportsService( const OUString & rServiceName )
202 	throw(::com::sun::star::uno::RuntimeException)
203 {
204 	const Sequence< OUString > & rSNL = getSupportedServiceNames();
205 	const OUString * pArray = rSNL.getConstArray();
206 	for ( sal_Int32 nPos = rSNL.getLength(); nPos--; )
207 	{
208 		if (pArray[nPos] == rServiceName)
209 			return sal_True;
210 	}
211 	return sal_False;
212 }
213 //__________________________________________________________________________________________________
214 Sequence< OUString > IdlReflectionServiceImpl::getSupportedServiceNames()
215 	throw(::com::sun::star::uno::RuntimeException)
216 {
217 	return core_getSupportedServiceNames();
218 }
219 
220 // XIdlReflection
221 //__________________________________________________________________________________________________
222 Reference< XIdlClass > IdlReflectionServiceImpl::getType( const Any & rObj )
223 	throw(::com::sun::star::uno::RuntimeException)
224 {
225 	return (rObj.hasValue() ? forType( rObj.getValueTypeRef() ) : Reference< XIdlClass >());
226 }
227 
228 //__________________________________________________________________________________________________
229 inline Reference< XIdlClass > IdlReflectionServiceImpl::constructClass(
230 	typelib_TypeDescription * pTypeDescr )
231 {
232 	OSL_ENSURE( pTypeDescr->eTypeClass != typelib_TypeClass_TYPEDEF, "### unexpected typedef!" );
233 
234 	switch (pTypeDescr->eTypeClass)
235 	{
236 	case typelib_TypeClass_VOID:
237 	case typelib_TypeClass_CHAR:
238 	case typelib_TypeClass_BOOLEAN:
239 	case typelib_TypeClass_BYTE:
240 	case typelib_TypeClass_SHORT:
241 	case typelib_TypeClass_UNSIGNED_SHORT:
242 	case typelib_TypeClass_LONG:
243 	case typelib_TypeClass_UNSIGNED_LONG:
244 	case typelib_TypeClass_HYPER:
245 	case typelib_TypeClass_UNSIGNED_HYPER:
246 	case typelib_TypeClass_FLOAT:
247 	case typelib_TypeClass_DOUBLE:
248 	case typelib_TypeClass_STRING:
249 	case typelib_TypeClass_ANY:
250 		return new IdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
251 
252 	case TypeClass_ENUM:
253 		return new EnumIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
254 
255 	case typelib_TypeClass_STRUCT:
256 	case typelib_TypeClass_UNION:
257 	case typelib_TypeClass_EXCEPTION:
258 		return new CompoundIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
259 
260 	case typelib_TypeClass_ARRAY:
261 	case typelib_TypeClass_SEQUENCE:
262 		return new ArrayIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
263 
264 	case typelib_TypeClass_INTERFACE:
265 		return new InterfaceIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
266 
267 	case typelib_TypeClass_TYPE:
268 		return new IdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
269 
270 	default:
271 #if OSL_DEBUG_LEVEL > 1
272 		OSL_TRACE( "### corereflection type unsupported: " );
273 		OString aName( OUStringToOString( pTypeDescr->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
274 		OSL_TRACE( aName.getStr() );
275 		OSL_TRACE( "\n" );
276 #endif
277         return Reference< XIdlClass >();
278 	}
279 }
280 //__________________________________________________________________________________________________
281 Reference< XIdlClass > IdlReflectionServiceImpl::forName( const OUString & rTypeName )
282 	throw(::com::sun::star::uno::RuntimeException)
283 {
284 	Reference< XIdlClass > xRet;
285 	Any aAny( _aElements.getValue( rTypeName ) );
286 
287 	if (aAny.hasValue())
288 	{
289 		if (aAny.getValueTypeClass() == TypeClass_INTERFACE)
290 			xRet = *(const Reference< XIdlClass > *)aAny.getValue();
291 	}
292 	else
293 	{
294 		// try to get _type_ by name
295 		typelib_TypeDescription * pTD = 0;
296 		typelib_typedescription_getByName( &pTD, rTypeName.pData );
297 		if (pTD)
298 		{
299 			if ((xRet = constructClass( pTD )).is())
300 				_aElements.setValue( rTypeName, makeAny( xRet ) ); // update
301 			typelib_typedescription_release( pTD );
302 		}
303 	}
304 
305 	return xRet;
306 }
307 
308 // XHierarchicalNameAccess
309 //__________________________________________________________________________________________________
310 Any IdlReflectionServiceImpl::getByHierarchicalName( const OUString & rName )
311 	throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException)
312 {
313 	Any aRet( _aElements.getValue( rName ) );
314 	if (! aRet.hasValue())
315 	{
316 		// first look for constants exclusivly!
317 		aRet = _xTDMgr->getByHierarchicalName( rName );
318 		if (aRet.getValueTypeClass() == TypeClass_INTERFACE) // if no constant,
319 															 // i.e. XTypeDescription for a type
320 		{
321 			// type retrieved from tdmgr
322 			OSL_ASSERT( (*(Reference< XInterface > *)aRet.getValue())->queryInterface(
323 				::getCppuType( (const Reference< XTypeDescription > *)0 ) ).hasValue() );
324 
325 			// if you are interested in a type then CALL forName()!!!
326 			// this way is NOT recommended for types, because this method looks for constants first
327 
328 			// if td manager found some type, it will be in the cache (hopefully.. we just got it)
329 			// so the second retrieving via c typelib callback chain should succeed...
330 
331 			// try to get _type_ by name
332 			typelib_TypeDescription * pTD = 0;
333 			typelib_typedescription_getByName( &pTD, rName.pData );
334 
335 			aRet.clear(); // kick XTypeDescription interface
336 
337 			if (pTD)
338 			{
339 				Reference< XIdlClass > xIdlClass( constructClass( pTD ) );
340 				aRet.setValue( &xIdlClass, ::getCppuType( (const Reference< XIdlClass > *)0 ) );
341 				typelib_typedescription_release( pTD );
342 			}
343 		}
344 		// else is constant
345 
346 		// update
347 		if (aRet.hasValue())
348 			_aElements.setValue( rName, aRet );
349 		else
350 		{
351 			throw NoSuchElementException( rName, Reference< XInterface >() );
352 		}
353 	}
354 	return aRet;
355 }
356 //__________________________________________________________________________________________________
357 sal_Bool IdlReflectionServiceImpl::hasByHierarchicalName( const OUString & rName )
358 	throw(::com::sun::star::uno::RuntimeException)
359 {
360 	try
361 	{
362 		return getByHierarchicalName( rName ).hasValue();
363 	}
364 	catch (NoSuchElementException &)
365 	{
366 	}
367 	return sal_False;
368 }
369 
370 //__________________________________________________________________________________________________
371 Reference< XIdlClass > IdlReflectionServiceImpl::forType( typelib_TypeDescription * pTypeDescr )
372 	throw(::com::sun::star::uno::RuntimeException)
373 {
374 	Reference< XIdlClass > xRet;
375 	OUString aName( pTypeDescr->pTypeName );
376 	Any aAny( _aElements.getValue( aName ) );
377 
378 	if (aAny.hasValue())
379 	{
380 		if (aAny.getValueTypeClass() == TypeClass_INTERFACE)
381 			xRet = *(const Reference< XIdlClass > *)aAny.getValue();
382 	}
383 	else
384 	{
385 		if (pTypeDescr && (xRet = constructClass( pTypeDescr )).is())
386 			_aElements.setValue( aName, makeAny( xRet ) ); // update
387 	}
388 
389 	return xRet;
390 }
391 //__________________________________________________________________________________________________
392 Reference< XIdlClass > IdlReflectionServiceImpl::forType( typelib_TypeDescriptionReference * pRef )
393 	throw(::com::sun::star::uno::RuntimeException)
394 {
395 	typelib_TypeDescription * pTD = 0;
396 	TYPELIB_DANGER_GET( &pTD, pRef );
397 	if (pTD)
398 	{
399 		Reference< XIdlClass > xRet = forType( pTD );
400 		TYPELIB_DANGER_RELEASE( pTD );
401 		return xRet;
402 	}
403 	throw RuntimeException(
404 		OUString( RTL_CONSTASCII_USTRINGPARAM("IdlReflectionServiceImpl::forType() failed!") ),
405 		(XWeak *)(OWeakObject *)this );
406 }
407 
408 //__________________________________________________________________________________________________
409 const Mapping & IdlReflectionServiceImpl::getCpp2Uno()
410 	throw(::com::sun::star::uno::RuntimeException)
411 {
412 	if (! _aCpp2Uno.is())
413 	{
414 		MutexGuard aGuard( getMutexAccess() );
415 		if (! _aCpp2Uno.is())
416 		{
417 			_aCpp2Uno = Mapping(
418                 OUString( RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME) ),
419                 OUString( RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO) ) );
420 			OSL_ENSURE( _aCpp2Uno.is(), "### cannot get c++ to uno mapping!" );
421 			if (! _aCpp2Uno.is())
422 			{
423 				throw RuntimeException(
424 					OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get c++ to uno mapping!") ),
425 					(XWeak *)(OWeakObject *)this );
426 			}
427 		}
428 	}
429 	return _aCpp2Uno;
430 }
431 //__________________________________________________________________________________________________
432 const Mapping & IdlReflectionServiceImpl::getUno2Cpp()
433 	throw(::com::sun::star::uno::RuntimeException)
434 {
435 	if (! _aUno2Cpp.is())
436 	{
437 		MutexGuard aGuard( getMutexAccess() );
438 		if (! _aUno2Cpp.is())
439 		{
440 			_aUno2Cpp = Mapping(
441                 OUString( RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO) ),
442                 OUString( RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME) ) );
443 			OSL_ENSURE( _aUno2Cpp.is(), "### cannot get uno to c++ mapping!" );
444 			if (! _aUno2Cpp.is())
445 			{
446 				throw RuntimeException(
447 					OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get uno to c++ mapping!") ),
448 					(XWeak *)(OWeakObject *)this );
449 			}
450 		}
451 	}
452 	return _aUno2Cpp;
453 }
454 //__________________________________________________________________________________________________
455 uno_Interface * IdlReflectionServiceImpl::mapToUno(
456     const Any & rObj, typelib_InterfaceTypeDescription * pTo )
457 	throw(::com::sun::star::uno::RuntimeException)
458 {
459 	Reference< XInterface > xObj;
460 	if (extract( rObj, pTo, xObj, this ))
461 		return (uno_Interface *)getCpp2Uno().mapInterface( xObj.get(), pTo );
462 
463 	throw RuntimeException(
464 		OUString( RTL_CONSTASCII_USTRINGPARAM("illegal object given!") ),
465 		(XWeak *)(OWeakObject *)this );
466 }
467 
468 //==================================================================================================
469 Reference< XInterface > SAL_CALL IdlReflectionServiceImpl_create(
470 	const Reference< XComponentContext > & xContext )
471 	throw(::com::sun::star::uno::Exception)
472 {
473 	return Reference< XInterface >( (XWeak *)(OWeakObject *)new IdlReflectionServiceImpl( xContext ) );
474 }
475 
476 }
477 
478 
479 //##################################################################################################
480 //##################################################################################################
481 //##################################################################################################
482 
483 using namespace stoc_corefl;
484 
485 static struct ImplementationEntry g_entries[] =
486 {
487 	{
488 		IdlReflectionServiceImpl_create, core_getImplementationName,
489 		core_getSupportedServiceNames, createSingleComponentFactory,
490 		&g_moduleCount.modCnt , 0
491 	},
492 	{ 0, 0, 0, 0, 0, 0 }
493 };
494 
495 extern "C"
496 {
497 sal_Bool SAL_CALL component_canUnload( TimeValue *pTime )
498 {
499 	return g_moduleCount.canUnload( &g_moduleCount , pTime );
500 }
501 
502 //==================================================================================================
503 void SAL_CALL component_getImplementationEnvironment(
504 	const sal_Char ** ppEnvTypeName, uno_Environment ** )
505 {
506 	*ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
507 }
508 //==================================================================================================
509 void * SAL_CALL component_getFactory(
510 	const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
511 {
512 	return component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
513 }
514 }
515