1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: lbmap.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_cppu.hxx"
34 #include "IdentityMapping.hxx"
40 #include "rtl/unload.h"
41 #include "rtl/ustring.hxx"
42 #include "rtl/ustrbuf.hxx"
43 #include "osl/module.h"
44 #include "osl/diagnose.h"
45 #include "osl/mutex.hxx"
46 #include "osl/interlck.h"
48 #include "uno/dispatcher.h"
49 #include "uno/mapping.h"
50 #include "uno/lbnames.h"
51 #include "uno/environment.hxx"
53 #include "typelib/typedescription.h"
55 #include "cppu/EnvDcp.hxx"
56 #include "cascade_mapping.hxx"
57 #include "IdentityMapping.hxx"
58 #include "loadmodule.hxx"
63 using namespace com::sun::star::uno
;
71 uno_Mapping
* _pMapping
;
74 inline Mapping( uno_Mapping
* pMapping
= 0 ) SAL_THROW( () );
75 inline Mapping( const Mapping
& rMapping
) SAL_THROW( () );
76 inline ~Mapping() SAL_THROW( () );
77 inline Mapping
& SAL_CALL
operator = ( uno_Mapping
* pMapping
) SAL_THROW( () );
78 inline Mapping
& SAL_CALL
operator = ( const Mapping
& rMapping
) SAL_THROW( () )
79 { return operator = ( rMapping
._pMapping
); }
80 inline uno_Mapping
* SAL_CALL
get() const SAL_THROW( () )
82 inline sal_Bool SAL_CALL
is() const SAL_THROW( () )
83 { return (_pMapping
!= 0); }
85 //__________________________________________________________________________________________________
86 inline Mapping::Mapping( uno_Mapping
* pMapping
) SAL_THROW( () )
87 : _pMapping( pMapping
)
90 (*_pMapping
->acquire
)( _pMapping
);
92 //__________________________________________________________________________________________________
93 inline Mapping::Mapping( const Mapping
& rMapping
) SAL_THROW( () )
94 : _pMapping( rMapping
._pMapping
)
97 (*_pMapping
->acquire
)( _pMapping
);
99 //__________________________________________________________________________________________________
100 inline Mapping::~Mapping() SAL_THROW( () )
103 (*_pMapping
->release
)( _pMapping
);
105 //__________________________________________________________________________________________________
106 inline Mapping
& Mapping::operator = ( uno_Mapping
* pMapping
) SAL_THROW( () )
109 (*pMapping
->acquire
)( pMapping
);
111 (*_pMapping
->release
)( _pMapping
);
112 _pMapping
= pMapping
;
116 //==================================================================================================
120 uno_Mapping
* pMapping
;
121 uno_freeMappingFunc freeMapping
;
122 OUString aMappingName
;
125 uno_Mapping
* pMapping_
, uno_freeMappingFunc freeMapping_
,
126 const OUString
& rMappingName_
)
129 , pMapping( pMapping_
)
130 , freeMapping( freeMapping_
)
131 , aMappingName( rMappingName_
)
134 //--------------------------------------------------------------------------------------------------
135 struct FctOUStringHash
: public unary_function
< const OUString
&, size_t >
137 size_t operator()( const OUString
& rKey
) const SAL_THROW( () )
138 { return (size_t)rKey
.hashCode(); }
140 //--------------------------------------------------------------------------------------------------
141 struct FctPtrHash
: public unary_function
< uno_Mapping
*, size_t >
143 size_t operator()( uno_Mapping
* pKey
) const SAL_THROW( () )
144 { return (size_t)pKey
; }
148 OUString
, MappingEntry
*, FctOUStringHash
, equal_to
< OUString
> > t_OUString2Entry
;
150 uno_Mapping
*, MappingEntry
*, FctPtrHash
, equal_to
< uno_Mapping
* > > t_Mapping2Entry
;
152 typedef set
< uno_getMappingFunc
> t_CallbackSet
;
153 typedef set
< OUString
> t_OUStringSet
;
155 //==================================================================================================
158 Mutex aMappingsMutex
;
159 t_OUString2Entry aName2Entry
;
160 t_Mapping2Entry aMapping2Entry
;
162 Mutex aCallbacksMutex
;
163 t_CallbackSet aCallbacks
;
165 Mutex aNegativeLibsMutex
;
166 t_OUStringSet aNegativeLibs
;
168 //--------------------------------------------------------------------------------------------------
169 static MappingsData
& getMappingsData() SAL_THROW( () )
171 static MappingsData
* s_p
= 0;
174 MutexGuard
aGuard( Mutex::getGlobalMutex() );
177 //TODO This memory is leaked; see #i63473# for when this should be
179 s_p
= new MappingsData
;
186 * This class mediates two different mapping via uno, e.g. form any language to uno,
187 * then from uno to any other language.
189 struct uno_Mediate_Mapping
: public uno_Mapping
199 OUString aAddPurpose
;
202 const Environment
& rFrom_
, const Environment
& rTo_
,
203 const Mapping
& rFrom2Uno_
, const Mapping
& rUno2To_
,
204 const OUString
& rAddPurpose
)
209 //--------------------------------------------------------------------------------------------------
210 static void SAL_CALL
mediate_free( uno_Mapping
* pMapping
)
213 delete static_cast< uno_Mediate_Mapping
* >( pMapping
);
215 //--------------------------------------------------------------------------------------------------
216 static void SAL_CALL
mediate_acquire( uno_Mapping
* pMapping
)
219 if (1 == ::osl_incrementInterlockedCount(
220 & static_cast< uno_Mediate_Mapping
* >( pMapping
)->nRef
))
223 &pMapping
, mediate_free
,
224 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aFrom
.get(),
225 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aTo
.get(),
226 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aAddPurpose
.pData
);
229 //--------------------------------------------------------------------------------------------------
230 static void SAL_CALL
mediate_release( uno_Mapping
* pMapping
)
233 if (! ::osl_decrementInterlockedCount(
234 & static_cast< uno_Mediate_Mapping
* >( pMapping
)->nRef
))
236 uno_revokeMapping( pMapping
);
239 //--------------------------------------------------------------------------------------------------
240 static void SAL_CALL
mediate_mapInterface(
241 uno_Mapping
* pMapping
,
242 void ** ppOut
, void * pInterface
,
243 typelib_InterfaceTypeDescription
* pInterfaceTypeDescr
)
246 OSL_ENSURE( pMapping
&& ppOut
, "### null ptr!" );
247 if (pMapping
&& ppOut
)
249 uno_Mediate_Mapping
* that
= static_cast< uno_Mediate_Mapping
* >( pMapping
);
250 uno_Mapping
* pFrom2Uno
= that
->aFrom2Uno
.get();
252 uno_Interface
* pUnoI
= 0;
253 (*pFrom2Uno
->mapInterface
)( pFrom2Uno
, (void **) &pUnoI
, pInterface
, pInterfaceTypeDescr
);
256 void * pOut
= *ppOut
;
259 uno_ExtEnvironment
* pTo
= that
->aTo
.get()->pExtEnv
;
260 OSL_ENSURE( 0 != pTo
, "### cannot release out interface: leaking!" );
262 (*pTo
->releaseInterface
)( pTo
, pOut
);
263 *ppOut
= 0; // set to 0 anyway, because mapping was not successfull!
268 uno_Mapping
* pUno2To
= that
->aUno2To
.get();
269 (*pUno2To
->mapInterface
)( pUno2To
, ppOut
, pUnoI
, pInterfaceTypeDescr
);
270 (*pUnoI
->release
)( pUnoI
);
275 //__________________________________________________________________________________________________
276 uno_Mediate_Mapping::uno_Mediate_Mapping(
277 const Environment
& rFrom_
, const Environment
& rTo_
,
278 const Mapping
& rFrom2Uno_
, const Mapping
& rUno2To_
,
279 const OUString
& rAddPurpose_
)
284 , aFrom2Uno( rFrom2Uno_
)
285 , aUno2To( rUno2To_
)
286 , aAddPurpose( rAddPurpose_
)
288 uno_Mapping::acquire
= mediate_acquire
;
289 uno_Mapping::release
= mediate_release
;
290 uno_Mapping::mapInterface
= mediate_mapInterface
;
293 //==================================================================================================
294 static inline OUString
getMappingName(
295 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
298 OUStringBuffer
aKey( 64 );
299 aKey
.append( rAddPurpose
);
300 aKey
.append( (sal_Unicode
)';' );
301 aKey
.append( rFrom
.getTypeName() );
302 aKey
.append( (sal_Unicode
)'[' );
303 aKey
.append( reinterpret_cast< sal_IntPtr
>(rFrom
.get()), 16 );
304 aKey
.appendAscii( RTL_CONSTASCII_STRINGPARAM("];") );
305 aKey
.append( rTo
.getTypeName() );
306 aKey
.append( (sal_Unicode
)'[' );
307 aKey
.append( reinterpret_cast< sal_IntPtr
>(rTo
.get()), 16 );
308 aKey
.append( (sal_Unicode
)']' );
309 return aKey
.makeStringAndClear();
311 //==================================================================================================
312 static inline OUString
getBridgeName(
313 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
316 OUStringBuffer
aBridgeName( 16 );
317 if (rAddPurpose
.getLength())
319 aBridgeName
.append( rAddPurpose
);
320 aBridgeName
.append( (sal_Unicode
)'_' );
322 aBridgeName
.append( EnvDcp::getTypeName(rFrom
.getTypeName()) );
323 aBridgeName
.append( (sal_Unicode
)'_' );
324 aBridgeName
.append( EnvDcp::getTypeName(rTo
.getTypeName()) );
325 return aBridgeName
.makeStringAndClear();
327 //==================================================================================================
328 static inline void setNegativeBridge( const OUString
& rBridgeName
)
331 MappingsData
& rData
= getMappingsData();
332 MutexGuard
aGuard( rData
.aNegativeLibsMutex
);
333 rData
.aNegativeLibs
.insert( rBridgeName
);
335 //==================================================================================================
336 static inline oslModule
loadModule( const OUString
& rBridgeName
)
341 MappingsData
& rData
= getMappingsData();
342 MutexGuard
aGuard( rData
.aNegativeLibsMutex
);
343 const t_OUStringSet::const_iterator
iFind( rData
.aNegativeLibs
.find( rBridgeName
) );
344 bNeg
= (iFind
!= rData
.aNegativeLibs
.end());
349 oslModule hModule
= cppu::detail::loadModule( rBridgeName
);
354 setNegativeBridge( rBridgeName
); // no load again
358 //==================================================================================================
359 static Mapping
loadExternalMapping(
360 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
363 OSL_ASSERT( rFrom
.is() && rTo
.is() );
364 if (rFrom
.is() && rTo
.is())
367 oslModule hModule
= 0;
370 if (EnvDcp::getTypeName(rFrom
.getTypeName()).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO
) ))
371 hModule
= loadModule( aName
= getBridgeName( rTo
, rFrom
, rAddPurpose
) );
373 hModule
= loadModule( aName
= getBridgeName( rFrom
, rTo
, rAddPurpose
) );
375 hModule
= loadModule( aName
= getBridgeName( rTo
, rFrom
, rAddPurpose
) );
379 OUString
aSymbolName( RTL_CONSTASCII_USTRINGPARAM(UNO_EXT_GETMAPPING
) );
380 uno_ext_getMappingFunc fpGetMapFunc
=
381 (uno_ext_getMappingFunc
)::osl_getFunctionSymbol(
382 hModule
, aSymbolName
.pData
);
387 (*fpGetMapFunc
)( (uno_Mapping
**)&aExt
, rFrom
.get(), rTo
.get() );
388 OSL_ASSERT( aExt
.is() );
391 ::rtl_registerModuleForUnloading( hModule
);
395 ::osl_unloadModule( hModule
);
396 setNegativeBridge( aName
);
402 //==================================================================================================
403 static Mapping
getDirectMapping(
404 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
= OUString() )
407 OSL_ASSERT( rFrom
.is() && rTo
.is() );
408 if (rFrom
.is() && rTo
.is())
410 MappingsData
& rData
= getMappingsData();
411 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
413 // try to find registered mapping
414 const t_OUString2Entry::const_iterator
iFind( rData
.aName2Entry
.find(
415 getMappingName( rFrom
, rTo
, rAddPurpose
) ) );
417 if (iFind
== rData
.aName2Entry
.end())
420 return loadExternalMapping( rFrom
, rTo
, rAddPurpose
);
424 return Mapping( (*iFind
).second
->pMapping
);
430 //--------------------------------------------------------------------------------------------------
431 static inline Mapping
createMediateMapping(
432 const Environment
& rFrom
, const Environment
& rTo
,
433 const Mapping
& rFrom2Uno
, const Mapping
& rUno2To
,
434 const OUString
& rAddPurpose
)
437 uno_Mapping
* pRet
= new uno_Mediate_Mapping(
438 rFrom
, rTo
, rFrom2Uno
, rUno2To
, rAddPurpose
); // ref count initially 1
440 &pRet
, mediate_free
, rFrom
.get(), rTo
.get(), rAddPurpose
.pData
);
441 Mapping
aRet( pRet
);
442 (*pRet
->release
)( pRet
);
445 //==================================================================================================
446 static Mapping
getMediateMapping(
447 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
453 // backwards: from dest to source of mapping chain
456 OUString
aUnoEnvTypeName( RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO
) );
457 if (rTo
.getTypeName() == aUnoEnvTypeName
) // to is uno
460 // no Uno2To mapping necessary
464 // get registered uno env
465 ::uno_getEnvironment( (uno_Environment
**)&aUno
, aUnoEnvTypeName
.pData
, 0 );
467 aUno2To
= getDirectMapping( aUno
, rTo
);
474 if (rAddPurpose
.getLength()) // insert purpose mapping between new ano_uno <-> uno
476 // create anonymous uno env
478 ::uno_createEnvironment( (uno_Environment
**)&aAnUno
, aUnoEnvTypeName
.pData
, 0 );
480 Mapping
aAnUno2Uno( getDirectMapping( aAnUno
, aUno
, rAddPurpose
) );
481 if (! aAnUno2Uno
.is())
484 if (aUno2To
.is()) // to is not uno
486 // create another purposed mediate mapping
487 aUno2To
= createMediateMapping( aAnUno
, rTo
, aAnUno2Uno
, aUno2To
, rAddPurpose
);
488 // : ano_uno <-> uno <-> to
492 aUno2To
= aAnUno2Uno
;
493 // : ano_uno <-> to (i.e., uno)
498 Mapping
aFrom2Uno( getDirectMapping( rFrom
, aUno
) );
499 if (aFrom2Uno
.is() && aUno2To
.is())
501 return createMediateMapping( rFrom
, rTo
, aFrom2Uno
, aUno2To
, rAddPurpose
);
502 // : from <-> some uno ...
509 using namespace ::cppu
;
513 //##################################################################################################
514 void SAL_CALL
uno_getMapping(
515 uno_Mapping
** ppMapping
, uno_Environment
* pFrom
, uno_Environment
* pTo
,
516 rtl_uString
* pAddPurpose
)
519 OSL_ENSURE( ppMapping
&& pFrom
&& pTo
, "### null ptr!" );
522 (*(*ppMapping
)->release
)( *ppMapping
);
527 Environment
aFrom( pFrom
), aTo( pTo
);
529 OUString aAddPurpose
;
531 aAddPurpose
= pAddPurpose
;
533 MappingsData
& rData
= getMappingsData();
535 // try registered mapping
537 MutexGuard
aGuard( rData
.aMappingsMutex
);
538 const t_OUString2Entry::const_iterator
iFind( rData
.aName2Entry
.find(
539 getMappingName( aFrom
, aTo
, aAddPurpose
) ) );
540 if (iFind
!= rData
.aName2Entry
.end())
541 aRet
= (*iFind
).second
->pMapping
;
544 // See if an identity mapping does fit.
545 if (!aRet
.is() && pFrom
== pTo
&& !aAddPurpose
.getLength())
546 aRet
= createIdentityMapping(pFrom
);
550 getCascadeMapping(ppMapping
, pFrom
, pTo
, pAddPurpose
);
556 if (! aRet
.is()) // try callback chain
558 MutexGuard
aGuard( rData
.aCallbacksMutex
);
559 for ( t_CallbackSet::const_iterator
iPos( rData
.aCallbacks
.begin() );
560 iPos
!= rData
.aCallbacks
.end(); ++iPos
)
562 (**iPos
)( ppMapping
, pFrom
, pTo
, aAddPurpose
.pData
);
570 aRet
= loadExternalMapping( aFrom
, aTo
, aAddPurpose
); // direct try
572 aRet
= getMediateMapping( aFrom
, aTo
, aAddPurpose
); // try via uno
577 (*aRet
.get()->acquire
)( aRet
.get() );
578 *ppMapping
= aRet
.get();
581 //##################################################################################################
582 void SAL_CALL
uno_getMappingByName(
583 uno_Mapping
** ppMapping
, rtl_uString
* pFrom
, rtl_uString
* pTo
,
584 rtl_uString
* pAddPurpose
)
587 OSL_ENSURE( ppMapping
&& pFrom
&& pTo
, "### null ptr!" );
590 (*(*ppMapping
)->release
)( *ppMapping
);
594 uno_Environment
* pEFrom
= 0;
595 uno_getEnvironment( &pEFrom
, pFrom
, 0 );
596 OSL_ENSURE( pEFrom
, "### cannot get source environment!" );
599 uno_Environment
* pETo
= 0;
600 uno_getEnvironment( &pETo
, pTo
, 0 );
601 OSL_ENSURE( pETo
, "### cannot get target environment!" );
604 ::uno_getMapping( ppMapping
, pEFrom
, pETo
, pAddPurpose
);
605 (*pETo
->release
)( pETo
);
607 (*pEFrom
->release
)( pEFrom
);
611 //##################################################################################################
612 void SAL_CALL
uno_registerMapping(
613 uno_Mapping
** ppMapping
, uno_freeMappingFunc freeMapping
,
614 uno_Environment
* pFrom
, uno_Environment
* pTo
, rtl_uString
* pAddPurpose
)
617 MappingsData
& rData
= getMappingsData();
618 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
620 const t_Mapping2Entry::const_iterator
iFind( rData
.aMapping2Entry
.find( *ppMapping
) );
621 if (iFind
== rData
.aMapping2Entry
.end())
623 OUString
aMappingName(
624 getMappingName( pFrom
, pTo
, pAddPurpose
? OUString(pAddPurpose
) : OUString() ) );
625 #if OSL_DEBUG_LEVEL > 1
626 OString
cstr( OUStringToOString( aMappingName
, RTL_TEXTENCODING_ASCII_US
) );
627 OSL_TRACE( "> inserting new mapping: %s", cstr
.getStr() );
630 MappingEntry
* pEntry
= new MappingEntry( *ppMapping
, freeMapping
, aMappingName
);
631 rData
.aName2Entry
[ aMappingName
] = pEntry
;
632 rData
.aMapping2Entry
[ *ppMapping
] = pEntry
;
636 MappingEntry
* pEntry
= (*iFind
).second
;
639 if (pEntry
->pMapping
!= *ppMapping
) // exchange mapping to be registered
641 (*pEntry
->pMapping
->acquire
)( pEntry
->pMapping
);
642 --pEntry
->nRef
; // correct count; kill mapping to be registered
644 (*freeMapping
)( *ppMapping
);
645 *ppMapping
= pEntry
->pMapping
;
649 //##################################################################################################
650 void SAL_CALL
uno_revokeMapping(
651 uno_Mapping
* pMapping
)
654 MappingsData
& rData
= getMappingsData();
655 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
657 const t_Mapping2Entry::const_iterator
iFind( rData
.aMapping2Entry
.find( pMapping
) );
658 OSL_ASSERT( iFind
!= rData
.aMapping2Entry
.end() );
659 MappingEntry
* pEntry
= (*iFind
).second
;
660 if (! --pEntry
->nRef
)
662 rData
.aMapping2Entry
.erase( pEntry
->pMapping
);
663 rData
.aName2Entry
.erase( pEntry
->aMappingName
);
665 #if OSL_DEBUG_LEVEL > 1
666 OString
cstr( OUStringToOString( pEntry
->aMappingName
, RTL_TEXTENCODING_ASCII_US
) );
667 OSL_TRACE( "> revoking mapping %s", cstr
.getStr() );
669 (*pEntry
->freeMapping
)( pEntry
->pMapping
);
674 //##################################################################################################
675 void SAL_CALL
uno_registerMappingCallback(
676 uno_getMappingFunc pCallback
)
679 OSL_ENSURE( pCallback
, "### null ptr!" );
680 MappingsData
& rData
= getMappingsData();
681 MutexGuard
aGuard( rData
.aCallbacksMutex
);
682 rData
.aCallbacks
.insert( pCallback
);
684 //##################################################################################################
685 void SAL_CALL
uno_revokeMappingCallback(
686 uno_getMappingFunc pCallback
)
689 OSL_ENSURE( pCallback
, "### null ptr!" );
690 MappingsData
& rData
= getMappingsData();
691 MutexGuard
aGuard( rData
.aCallbacksMutex
);
692 rData
.aCallbacks
.erase( pCallback
);