1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_cppu.hxx"
31 #include "IdentityMapping.hxx"
37 #include "rtl/unload.h"
38 #include "rtl/ustring.hxx"
39 #include "rtl/ustrbuf.hxx"
40 #include "osl/module.h"
41 #include "osl/diagnose.h"
42 #include "osl/mutex.hxx"
43 #include "osl/interlck.h"
45 #include "uno/dispatcher.h"
46 #include "uno/mapping.h"
47 #include "uno/lbnames.h"
48 #include "uno/environment.hxx"
50 #include "typelib/typedescription.h"
52 #include "cppu/EnvDcp.hxx"
53 #include "cascade_mapping.hxx"
54 #include "IdentityMapping.hxx"
55 #include "loadmodule.hxx"
60 using namespace com::sun::star::uno
;
68 uno_Mapping
* _pMapping
;
71 inline Mapping( uno_Mapping
* pMapping
= 0 ) SAL_THROW( () );
72 inline Mapping( const Mapping
& rMapping
) SAL_THROW( () );
73 inline ~Mapping() SAL_THROW( () );
74 inline Mapping
& SAL_CALL
operator = ( uno_Mapping
* pMapping
) SAL_THROW( () );
75 inline Mapping
& SAL_CALL
operator = ( const Mapping
& rMapping
) SAL_THROW( () )
76 { return operator = ( rMapping
._pMapping
); }
77 inline uno_Mapping
* SAL_CALL
get() const SAL_THROW( () )
79 inline sal_Bool SAL_CALL
is() const SAL_THROW( () )
80 { return (_pMapping
!= 0); }
82 //__________________________________________________________________________________________________
83 inline Mapping::Mapping( uno_Mapping
* pMapping
) SAL_THROW( () )
84 : _pMapping( pMapping
)
87 (*_pMapping
->acquire
)( _pMapping
);
89 //__________________________________________________________________________________________________
90 inline Mapping::Mapping( const Mapping
& rMapping
) SAL_THROW( () )
91 : _pMapping( rMapping
._pMapping
)
94 (*_pMapping
->acquire
)( _pMapping
);
96 //__________________________________________________________________________________________________
97 inline Mapping::~Mapping() SAL_THROW( () )
100 (*_pMapping
->release
)( _pMapping
);
102 //__________________________________________________________________________________________________
103 inline Mapping
& Mapping::operator = ( uno_Mapping
* pMapping
) SAL_THROW( () )
106 (*pMapping
->acquire
)( pMapping
);
108 (*_pMapping
->release
)( _pMapping
);
109 _pMapping
= pMapping
;
113 //==================================================================================================
117 uno_Mapping
* pMapping
;
118 uno_freeMappingFunc freeMapping
;
119 OUString aMappingName
;
122 uno_Mapping
* pMapping_
, uno_freeMappingFunc freeMapping_
,
123 const OUString
& rMappingName_
)
126 , pMapping( pMapping_
)
127 , freeMapping( freeMapping_
)
128 , aMappingName( rMappingName_
)
131 //--------------------------------------------------------------------------------------------------
132 struct FctOUStringHash
: public unary_function
< const OUString
&, size_t >
134 size_t operator()( const OUString
& rKey
) const SAL_THROW( () )
135 { return (size_t)rKey
.hashCode(); }
137 //--------------------------------------------------------------------------------------------------
138 struct FctPtrHash
: public unary_function
< uno_Mapping
*, size_t >
140 size_t operator()( uno_Mapping
* pKey
) const SAL_THROW( () )
141 { return (size_t)pKey
; }
145 OUString
, MappingEntry
*, FctOUStringHash
, equal_to
< OUString
> > t_OUString2Entry
;
147 uno_Mapping
*, MappingEntry
*, FctPtrHash
, equal_to
< uno_Mapping
* > > t_Mapping2Entry
;
149 typedef set
< uno_getMappingFunc
> t_CallbackSet
;
150 typedef set
< OUString
> t_OUStringSet
;
152 //==================================================================================================
155 Mutex aMappingsMutex
;
156 t_OUString2Entry aName2Entry
;
157 t_Mapping2Entry aMapping2Entry
;
159 Mutex aCallbacksMutex
;
160 t_CallbackSet aCallbacks
;
162 Mutex aNegativeLibsMutex
;
163 t_OUStringSet aNegativeLibs
;
165 //--------------------------------------------------------------------------------------------------
166 static MappingsData
& getMappingsData() SAL_THROW( () )
168 static MappingsData
* s_p
= 0;
171 MutexGuard
aGuard( Mutex::getGlobalMutex() );
174 //TODO This memory is leaked; see #i63473# for when this should be
176 s_p
= new MappingsData
;
183 * This class mediates two different mapping via uno, e.g. form any language to uno,
184 * then from uno to any other language.
186 struct uno_Mediate_Mapping
: public uno_Mapping
196 OUString aAddPurpose
;
199 const Environment
& rFrom_
, const Environment
& rTo_
,
200 const Mapping
& rFrom2Uno_
, const Mapping
& rUno2To_
,
201 const OUString
& rAddPurpose
)
206 //--------------------------------------------------------------------------------------------------
207 static void SAL_CALL
mediate_free( uno_Mapping
* pMapping
)
210 delete static_cast< uno_Mediate_Mapping
* >( pMapping
);
212 //--------------------------------------------------------------------------------------------------
213 static void SAL_CALL
mediate_acquire( uno_Mapping
* pMapping
)
216 if (1 == ::osl_incrementInterlockedCount(
217 & static_cast< uno_Mediate_Mapping
* >( pMapping
)->nRef
))
220 &pMapping
, mediate_free
,
221 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aFrom
.get(),
222 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aTo
.get(),
223 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aAddPurpose
.pData
);
226 //--------------------------------------------------------------------------------------------------
227 static void SAL_CALL
mediate_release( uno_Mapping
* pMapping
)
230 if (! ::osl_decrementInterlockedCount(
231 & static_cast< uno_Mediate_Mapping
* >( pMapping
)->nRef
))
233 uno_revokeMapping( pMapping
);
236 //--------------------------------------------------------------------------------------------------
237 static void SAL_CALL
mediate_mapInterface(
238 uno_Mapping
* pMapping
,
239 void ** ppOut
, void * pInterface
,
240 typelib_InterfaceTypeDescription
* pInterfaceTypeDescr
)
243 OSL_ENSURE( pMapping
&& ppOut
, "### null ptr!" );
244 if (pMapping
&& ppOut
)
246 uno_Mediate_Mapping
* that
= static_cast< uno_Mediate_Mapping
* >( pMapping
);
247 uno_Mapping
* pFrom2Uno
= that
->aFrom2Uno
.get();
249 uno_Interface
* pUnoI
= 0;
250 (*pFrom2Uno
->mapInterface
)( pFrom2Uno
, (void **) &pUnoI
, pInterface
, pInterfaceTypeDescr
);
253 void * pOut
= *ppOut
;
256 uno_ExtEnvironment
* pTo
= that
->aTo
.get()->pExtEnv
;
257 OSL_ENSURE( 0 != pTo
, "### cannot release out interface: leaking!" );
259 (*pTo
->releaseInterface
)( pTo
, pOut
);
260 *ppOut
= 0; // set to 0 anyway, because mapping was not successfull!
265 uno_Mapping
* pUno2To
= that
->aUno2To
.get();
266 (*pUno2To
->mapInterface
)( pUno2To
, ppOut
, pUnoI
, pInterfaceTypeDescr
);
267 (*pUnoI
->release
)( pUnoI
);
272 //__________________________________________________________________________________________________
273 uno_Mediate_Mapping::uno_Mediate_Mapping(
274 const Environment
& rFrom_
, const Environment
& rTo_
,
275 const Mapping
& rFrom2Uno_
, const Mapping
& rUno2To_
,
276 const OUString
& rAddPurpose_
)
281 , aFrom2Uno( rFrom2Uno_
)
282 , aUno2To( rUno2To_
)
283 , aAddPurpose( rAddPurpose_
)
285 uno_Mapping::acquire
= mediate_acquire
;
286 uno_Mapping::release
= mediate_release
;
287 uno_Mapping::mapInterface
= mediate_mapInterface
;
290 //==================================================================================================
291 static inline OUString
getMappingName(
292 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
295 OUStringBuffer
aKey( 64 );
296 aKey
.append( rAddPurpose
);
297 aKey
.append( (sal_Unicode
)';' );
298 aKey
.append( rFrom
.getTypeName() );
299 aKey
.append( (sal_Unicode
)'[' );
300 aKey
.append( reinterpret_cast< sal_IntPtr
>(rFrom
.get()), 16 );
301 aKey
.appendAscii( RTL_CONSTASCII_STRINGPARAM("];") );
302 aKey
.append( rTo
.getTypeName() );
303 aKey
.append( (sal_Unicode
)'[' );
304 aKey
.append( reinterpret_cast< sal_IntPtr
>(rTo
.get()), 16 );
305 aKey
.append( (sal_Unicode
)']' );
306 return aKey
.makeStringAndClear();
308 //==================================================================================================
309 static inline OUString
getBridgeName(
310 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
313 OUStringBuffer
aBridgeName( 16 );
314 if (rAddPurpose
.getLength())
316 aBridgeName
.append( rAddPurpose
);
317 aBridgeName
.append( (sal_Unicode
)'_' );
319 aBridgeName
.append( EnvDcp::getTypeName(rFrom
.getTypeName()) );
320 aBridgeName
.append( (sal_Unicode
)'_' );
321 aBridgeName
.append( EnvDcp::getTypeName(rTo
.getTypeName()) );
322 return aBridgeName
.makeStringAndClear();
324 //==================================================================================================
325 static inline void setNegativeBridge( const OUString
& rBridgeName
)
328 MappingsData
& rData
= getMappingsData();
329 MutexGuard
aGuard( rData
.aNegativeLibsMutex
);
330 rData
.aNegativeLibs
.insert( rBridgeName
);
332 //==================================================================================================
333 static inline oslModule
loadModule( const OUString
& rBridgeName
)
338 MappingsData
& rData
= getMappingsData();
339 MutexGuard
aGuard( rData
.aNegativeLibsMutex
);
340 const t_OUStringSet::const_iterator
iFind( rData
.aNegativeLibs
.find( rBridgeName
) );
341 bNeg
= (iFind
!= rData
.aNegativeLibs
.end());
346 oslModule hModule
= cppu::detail::loadModule( rBridgeName
);
351 setNegativeBridge( rBridgeName
); // no load again
355 //==================================================================================================
356 static Mapping
loadExternalMapping(
357 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
360 OSL_ASSERT( rFrom
.is() && rTo
.is() );
361 if (rFrom
.is() && rTo
.is())
364 oslModule hModule
= 0;
367 if (EnvDcp::getTypeName(rFrom
.getTypeName()).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO
) ))
368 hModule
= loadModule( aName
= getBridgeName( rTo
, rFrom
, rAddPurpose
) );
370 hModule
= loadModule( aName
= getBridgeName( rFrom
, rTo
, rAddPurpose
) );
372 hModule
= loadModule( aName
= getBridgeName( rTo
, rFrom
, rAddPurpose
) );
376 OUString
aSymbolName( RTL_CONSTASCII_USTRINGPARAM(UNO_EXT_GETMAPPING
) );
377 uno_ext_getMappingFunc fpGetMapFunc
=
378 (uno_ext_getMappingFunc
)::osl_getFunctionSymbol(
379 hModule
, aSymbolName
.pData
);
384 (*fpGetMapFunc
)( (uno_Mapping
**)&aExt
, rFrom
.get(), rTo
.get() );
385 OSL_ASSERT( aExt
.is() );
388 ::rtl_registerModuleForUnloading( hModule
);
392 ::osl_unloadModule( hModule
);
393 setNegativeBridge( aName
);
399 //==================================================================================================
400 static Mapping
getDirectMapping(
401 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
= OUString() )
404 OSL_ASSERT( rFrom
.is() && rTo
.is() );
405 if (rFrom
.is() && rTo
.is())
407 MappingsData
& rData
= getMappingsData();
408 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
410 // try to find registered mapping
411 const t_OUString2Entry::const_iterator
iFind( rData
.aName2Entry
.find(
412 getMappingName( rFrom
, rTo
, rAddPurpose
) ) );
414 if (iFind
== rData
.aName2Entry
.end())
417 return loadExternalMapping( rFrom
, rTo
, rAddPurpose
);
421 return Mapping( (*iFind
).second
->pMapping
);
427 //--------------------------------------------------------------------------------------------------
428 static inline Mapping
createMediateMapping(
429 const Environment
& rFrom
, const Environment
& rTo
,
430 const Mapping
& rFrom2Uno
, const Mapping
& rUno2To
,
431 const OUString
& rAddPurpose
)
434 uno_Mapping
* pRet
= new uno_Mediate_Mapping(
435 rFrom
, rTo
, rFrom2Uno
, rUno2To
, rAddPurpose
); // ref count initially 1
437 &pRet
, mediate_free
, rFrom
.get(), rTo
.get(), rAddPurpose
.pData
);
438 Mapping
aRet( pRet
);
439 (*pRet
->release
)( pRet
);
442 //==================================================================================================
443 static Mapping
getMediateMapping(
444 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
450 // backwards: from dest to source of mapping chain
453 OUString
aUnoEnvTypeName( RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO
) );
454 if (rTo
.getTypeName() == aUnoEnvTypeName
) // to is uno
457 // no Uno2To mapping necessary
461 // get registered uno env
462 ::uno_getEnvironment( (uno_Environment
**)&aUno
, aUnoEnvTypeName
.pData
, 0 );
464 aUno2To
= getDirectMapping( aUno
, rTo
);
471 if (rAddPurpose
.getLength()) // insert purpose mapping between new ano_uno <-> uno
473 // create anonymous uno env
475 ::uno_createEnvironment( (uno_Environment
**)&aAnUno
, aUnoEnvTypeName
.pData
, 0 );
477 Mapping
aAnUno2Uno( getDirectMapping( aAnUno
, aUno
, rAddPurpose
) );
478 if (! aAnUno2Uno
.is())
481 if (aUno2To
.is()) // to is not uno
483 // create another purposed mediate mapping
484 aUno2To
= createMediateMapping( aAnUno
, rTo
, aAnUno2Uno
, aUno2To
, rAddPurpose
);
485 // : ano_uno <-> uno <-> to
489 aUno2To
= aAnUno2Uno
;
490 // : ano_uno <-> to (i.e., uno)
495 Mapping
aFrom2Uno( getDirectMapping( rFrom
, aUno
) );
496 if (aFrom2Uno
.is() && aUno2To
.is())
498 return createMediateMapping( rFrom
, rTo
, aFrom2Uno
, aUno2To
, rAddPurpose
);
499 // : from <-> some uno ...
506 using namespace ::cppu
;
510 //##################################################################################################
511 void SAL_CALL
uno_getMapping(
512 uno_Mapping
** ppMapping
, uno_Environment
* pFrom
, uno_Environment
* pTo
,
513 rtl_uString
* pAddPurpose
)
516 OSL_ENSURE( ppMapping
&& pFrom
&& pTo
, "### null ptr!" );
519 (*(*ppMapping
)->release
)( *ppMapping
);
524 Environment
aFrom( pFrom
), aTo( pTo
);
526 OUString aAddPurpose
;
528 aAddPurpose
= pAddPurpose
;
530 MappingsData
& rData
= getMappingsData();
532 // try registered mapping
534 MutexGuard
aGuard( rData
.aMappingsMutex
);
535 const t_OUString2Entry::const_iterator
iFind( rData
.aName2Entry
.find(
536 getMappingName( aFrom
, aTo
, aAddPurpose
) ) );
537 if (iFind
!= rData
.aName2Entry
.end())
538 aRet
= (*iFind
).second
->pMapping
;
541 // See if an identity mapping does fit.
542 if (!aRet
.is() && pFrom
== pTo
&& !aAddPurpose
.getLength())
543 aRet
= createIdentityMapping(pFrom
);
547 getCascadeMapping(ppMapping
, pFrom
, pTo
, pAddPurpose
);
553 if (! aRet
.is()) // try callback chain
555 MutexGuard
aGuard( rData
.aCallbacksMutex
);
556 for ( t_CallbackSet::const_iterator
iPos( rData
.aCallbacks
.begin() );
557 iPos
!= rData
.aCallbacks
.end(); ++iPos
)
559 (**iPos
)( ppMapping
, pFrom
, pTo
, aAddPurpose
.pData
);
567 aRet
= loadExternalMapping( aFrom
, aTo
, aAddPurpose
); // direct try
569 aRet
= getMediateMapping( aFrom
, aTo
, aAddPurpose
); // try via uno
574 (*aRet
.get()->acquire
)( aRet
.get() );
575 *ppMapping
= aRet
.get();
578 //##################################################################################################
579 void SAL_CALL
uno_getMappingByName(
580 uno_Mapping
** ppMapping
, rtl_uString
* pFrom
, rtl_uString
* pTo
,
581 rtl_uString
* pAddPurpose
)
584 OSL_ENSURE( ppMapping
&& pFrom
&& pTo
, "### null ptr!" );
587 (*(*ppMapping
)->release
)( *ppMapping
);
591 uno_Environment
* pEFrom
= 0;
592 uno_getEnvironment( &pEFrom
, pFrom
, 0 );
593 OSL_ENSURE( pEFrom
, "### cannot get source environment!" );
596 uno_Environment
* pETo
= 0;
597 uno_getEnvironment( &pETo
, pTo
, 0 );
598 OSL_ENSURE( pETo
, "### cannot get target environment!" );
601 ::uno_getMapping( ppMapping
, pEFrom
, pETo
, pAddPurpose
);
602 (*pETo
->release
)( pETo
);
604 (*pEFrom
->release
)( pEFrom
);
608 //##################################################################################################
609 void SAL_CALL
uno_registerMapping(
610 uno_Mapping
** ppMapping
, uno_freeMappingFunc freeMapping
,
611 uno_Environment
* pFrom
, uno_Environment
* pTo
, rtl_uString
* pAddPurpose
)
614 MappingsData
& rData
= getMappingsData();
615 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
617 const t_Mapping2Entry::const_iterator
iFind( rData
.aMapping2Entry
.find( *ppMapping
) );
618 if (iFind
== rData
.aMapping2Entry
.end())
620 OUString
aMappingName(
621 getMappingName( pFrom
, pTo
, pAddPurpose
? OUString(pAddPurpose
) : OUString() ) );
622 #if OSL_DEBUG_LEVEL > 1
623 OString
cstr( OUStringToOString( aMappingName
, RTL_TEXTENCODING_ASCII_US
) );
624 OSL_TRACE( "> inserting new mapping: %s", cstr
.getStr() );
627 MappingEntry
* pEntry
= new MappingEntry( *ppMapping
, freeMapping
, aMappingName
);
628 rData
.aName2Entry
[ aMappingName
] = pEntry
;
629 rData
.aMapping2Entry
[ *ppMapping
] = pEntry
;
633 MappingEntry
* pEntry
= (*iFind
).second
;
636 if (pEntry
->pMapping
!= *ppMapping
) // exchange mapping to be registered
638 (*pEntry
->pMapping
->acquire
)( pEntry
->pMapping
);
639 --pEntry
->nRef
; // correct count; kill mapping to be registered
641 (*freeMapping
)( *ppMapping
);
642 *ppMapping
= pEntry
->pMapping
;
646 //##################################################################################################
647 void SAL_CALL
uno_revokeMapping(
648 uno_Mapping
* pMapping
)
651 MappingsData
& rData
= getMappingsData();
652 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
654 const t_Mapping2Entry::const_iterator
iFind( rData
.aMapping2Entry
.find( pMapping
) );
655 OSL_ASSERT( iFind
!= rData
.aMapping2Entry
.end() );
656 MappingEntry
* pEntry
= (*iFind
).second
;
657 if (! --pEntry
->nRef
)
659 rData
.aMapping2Entry
.erase( pEntry
->pMapping
);
660 rData
.aName2Entry
.erase( pEntry
->aMappingName
);
662 #if OSL_DEBUG_LEVEL > 1
663 OString
cstr( OUStringToOString( pEntry
->aMappingName
, RTL_TEXTENCODING_ASCII_US
) );
664 OSL_TRACE( "> revoking mapping %s", cstr
.getStr() );
666 (*pEntry
->freeMapping
)( pEntry
->pMapping
);
671 //##################################################################################################
672 void SAL_CALL
uno_registerMappingCallback(
673 uno_getMappingFunc pCallback
)
676 OSL_ENSURE( pCallback
, "### null ptr!" );
677 MappingsData
& rData
= getMappingsData();
678 MutexGuard
aGuard( rData
.aCallbacksMutex
);
679 rData
.aCallbacks
.insert( pCallback
);
681 //##################################################################################################
682 void SAL_CALL
uno_revokeMappingCallback(
683 uno_getMappingFunc pCallback
)
686 OSL_ENSURE( pCallback
, "### null ptr!" );
687 MappingsData
& rData
= getMappingsData();
688 MutexGuard
aGuard( rData
.aCallbacksMutex
);
689 rData
.aCallbacks
.erase( pCallback
);