Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "osl/diagnose.h"
22 : #include "osl/interlck.h"
23 : #include "osl/doublecheckedlocking.h"
24 : #include "osl/mutex.hxx"
25 : #include "rtl/ref.hxx"
26 : #include "uno/dispatcher.hxx"
27 : #include "uno/data.h"
28 : #include <uno/lbnames.h>
29 : #include "uno/mapping.hxx"
30 : #include "uno/environment.hxx"
31 : #include "typelib/typedescription.hxx"
32 : #include "cppuhelper/exc_hlp.hxx"
33 : #include "cppuhelper/implbase2.hxx"
34 : #include "cppuhelper/implementationentry.hxx"
35 : #include "cppuhelper/factory.hxx"
36 : #include <cppuhelper/supportsservice.hxx>
37 : #include "com/sun/star/lang/XServiceInfo.hpp"
38 : #include "com/sun/star/registry/XRegistryKey.hpp"
39 : #include "com/sun/star/reflection/XProxyFactory.hpp"
40 : #include "com/sun/star/uno/RuntimeException.hpp"
41 :
42 : #define SERVICE_NAME "com.sun.star.reflection.ProxyFactory"
43 : #define IMPL_NAME "com.sun.star.comp.reflection.ProxyFactory"
44 :
45 :
46 : using namespace ::com::sun::star;
47 : using namespace ::com::sun::star::uno;
48 :
49 :
50 : namespace
51 : {
52 :
53 0 : static OUString proxyfac_getImplementationName()
54 : {
55 0 : return OUString(IMPL_NAME);
56 : }
57 :
58 0 : static Sequence< OUString > proxyfac_getSupportedServiceNames()
59 : {
60 0 : OUString str_name = SERVICE_NAME;
61 0 : return Sequence< OUString >( &str_name, 1 );
62 : }
63 :
64 :
65 : struct FactoryImpl : public ::cppu::WeakImplHelper2< lang::XServiceInfo,
66 : reflection::XProxyFactory >
67 : {
68 : Environment m_uno_env;
69 : Environment m_cpp_env;
70 : Mapping m_uno2cpp;
71 : Mapping m_cpp2uno;
72 :
73 : UnoInterfaceReference binuno_queryInterface(
74 : UnoInterfaceReference const & unoI,
75 : typelib_InterfaceTypeDescription * pTypeDescr );
76 :
77 : FactoryImpl();
78 : virtual ~FactoryImpl();
79 :
80 : // XServiceInfo
81 : virtual OUString SAL_CALL getImplementationName()
82 : throw (RuntimeException, std::exception) SAL_OVERRIDE;
83 : virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName )
84 : throw (RuntimeException, std::exception) SAL_OVERRIDE;
85 : virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
86 : throw (RuntimeException, std::exception) SAL_OVERRIDE;
87 :
88 : // XProxyFactory
89 : virtual Reference< XAggregation > SAL_CALL createProxy(
90 : Reference< XInterface > const & xTarget )
91 : throw (RuntimeException, std::exception) SAL_OVERRIDE;
92 : };
93 :
94 :
95 0 : UnoInterfaceReference FactoryImpl::binuno_queryInterface(
96 : UnoInterfaceReference const & unoI,
97 : typelib_InterfaceTypeDescription * pTypeDescr )
98 : {
99 : // init queryInterface() td
100 : static typelib_TypeDescription * s_pQITD = 0;
101 0 : if (s_pQITD == 0)
102 : {
103 0 : ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
104 0 : if (s_pQITD == 0)
105 : {
106 0 : typelib_TypeDescription * pTXInterfaceDescr = 0;
107 : TYPELIB_DANGER_GET(
108 : &pTXInterfaceDescr,
109 : ::getCppuType( reinterpret_cast< Reference< XInterface >
110 0 : const * >(0) ).getTypeLibType() );
111 0 : typelib_TypeDescription * pQITD = 0;
112 : typelib_typedescriptionreference_getDescription(
113 : &pQITD, reinterpret_cast< typelib_InterfaceTypeDescription * >(
114 0 : pTXInterfaceDescr )->ppAllMembers[ 0 ] );
115 0 : TYPELIB_DANGER_RELEASE( pTXInterfaceDescr );
116 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
117 0 : s_pQITD = pQITD;
118 0 : }
119 : }
120 : else
121 : {
122 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
123 : }
124 :
125 : void * args[ 1 ];
126 : args[ 0 ] = &reinterpret_cast< typelib_TypeDescription * >(
127 0 : pTypeDescr )->pWeakRef;
128 : uno_Any ret_val, exc_space;
129 0 : uno_Any * exc = &exc_space;
130 :
131 0 : unoI.dispatch( s_pQITD, &ret_val, args, &exc );
132 :
133 0 : if (exc == 0)
134 : {
135 0 : UnoInterfaceReference ret;
136 0 : if (ret_val.pType->eTypeClass == typelib_TypeClass_INTERFACE)
137 : {
138 : ret.set( *reinterpret_cast< uno_Interface ** >(ret_val.pData),
139 0 : SAL_NO_ACQUIRE );
140 0 : typelib_typedescriptionreference_release( ret_val.pType );
141 : }
142 : else
143 : {
144 0 : uno_any_destruct( &ret_val, 0 );
145 : }
146 0 : return ret;
147 : }
148 : else
149 : {
150 : // exception occurred:
151 : OSL_ENSURE(
152 : typelib_typedescriptionreference_isAssignableFrom(
153 : ::getCppuType( reinterpret_cast<
154 : RuntimeException const * >(0) ).getTypeLibType(),
155 : exc->pType ),
156 : "### RuntimeException expected!" );
157 0 : Any cpp_exc;
158 : uno_type_copyAndConvertData(
159 0 : &cpp_exc, exc, ::getCppuType( &cpp_exc ).getTypeLibType(),
160 0 : m_uno2cpp.get() );
161 0 : uno_any_destruct( exc, 0 );
162 0 : ::cppu::throwException( cpp_exc );
163 : OSL_ASSERT( false ); // way of no return
164 0 : return UnoInterfaceReference(); // for dummy
165 : }
166 : }
167 :
168 :
169 : struct ProxyRoot : public ::cppu::OWeakAggObject
170 : {
171 : // XAggregation
172 : virtual Any SAL_CALL queryAggregation( Type const & rType )
173 : throw (RuntimeException, std::exception) SAL_OVERRIDE;
174 :
175 : virtual ~ProxyRoot();
176 : inline ProxyRoot( ::rtl::Reference< FactoryImpl > const & factory,
177 : Reference< XInterface > const & xTarget );
178 :
179 : ::rtl::Reference< FactoryImpl > m_factory;
180 :
181 : private:
182 : UnoInterfaceReference m_target;
183 : };
184 :
185 :
186 0 : struct binuno_Proxy : public uno_Interface
187 : {
188 : oslInterlockedCount m_nRefCount;
189 : ::rtl::Reference< ProxyRoot > m_root;
190 : UnoInterfaceReference m_target;
191 : OUString m_oid;
192 : TypeDescription m_typeDescr;
193 :
194 : inline binuno_Proxy(
195 : ::rtl::Reference< ProxyRoot > const & root,
196 : UnoInterfaceReference const & target,
197 : OUString const & oid, TypeDescription const & typeDescr );
198 : };
199 :
200 : extern "C"
201 : {
202 :
203 :
204 0 : static void SAL_CALL binuno_proxy_free(
205 : uno_ExtEnvironment * pEnv, void * pProxy )
206 : {
207 : (void) pEnv; // avoid warning about unused parameter
208 : binuno_Proxy * proxy = static_cast< binuno_Proxy * >(
209 0 : reinterpret_cast< uno_Interface * >( pProxy ) );
210 : OSL_ASSERT( proxy->m_root->m_factory->m_uno_env.get()->pExtEnv == pEnv );
211 0 : delete proxy;
212 0 : }
213 :
214 :
215 0 : static void SAL_CALL binuno_proxy_acquire( uno_Interface * pUnoI )
216 : {
217 0 : binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
218 0 : if (osl_atomic_increment( &that->m_nRefCount ) == 1)
219 : {
220 : // rebirth of zombie
221 : uno_ExtEnvironment * uno_env =
222 0 : that->m_root->m_factory->m_uno_env.get()->pExtEnv;
223 : OSL_ASSERT( uno_env != 0 );
224 : (*uno_env->registerProxyInterface)(
225 : uno_env, reinterpret_cast< void ** >( &pUnoI ), binuno_proxy_free,
226 : that->m_oid.pData,
227 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
228 0 : that->m_typeDescr.get() ) );
229 : OSL_ASSERT( that == static_cast< binuno_Proxy * >( pUnoI ) );
230 : }
231 0 : }
232 :
233 :
234 0 : static void SAL_CALL binuno_proxy_release( uno_Interface * pUnoI )
235 : {
236 0 : binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
237 0 : if (osl_atomic_decrement( &that->m_nRefCount ) == 0)
238 : {
239 : uno_ExtEnvironment * uno_env =
240 0 : that->m_root->m_factory->m_uno_env.get()->pExtEnv;
241 : OSL_ASSERT( uno_env != 0 );
242 0 : (*uno_env->revokeInterface)( uno_env, pUnoI );
243 : }
244 0 : }
245 :
246 :
247 0 : static void SAL_CALL binuno_proxy_dispatch(
248 : uno_Interface * pUnoI, const typelib_TypeDescription * pMemberType,
249 : void * pReturn, void * pArgs [], uno_Any ** ppException )
250 : {
251 0 : binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
252 0 : switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription const * >(
253 : pMemberType )->nPosition)
254 : {
255 : case 0: // queryInterface()
256 : {
257 : try
258 : {
259 : Type const & rType =
260 0 : *reinterpret_cast< Type const * >( pArgs[ 0 ] );
261 0 : Any ret( that->m_root->queryInterface( rType ) );
262 : uno_type_copyAndConvertData(
263 0 : pReturn, &ret, ::getCppuType( &ret ).getTypeLibType(),
264 0 : that->m_root->m_factory->m_cpp2uno.get() );
265 0 : *ppException = 0; // no exc
266 : }
267 0 : catch (RuntimeException &)
268 : {
269 0 : Any exc( ::cppu::getCaughtException() );
270 : uno_type_any_constructAndConvert(
271 0 : *ppException, const_cast< void * >(exc.getValue()),
272 : exc.getValueTypeRef(),
273 0 : that->m_root->m_factory->m_cpp2uno.get() );
274 : }
275 0 : break;
276 : }
277 : case 1: // acquire()
278 0 : binuno_proxy_acquire( pUnoI );
279 0 : *ppException = 0; // no exc
280 0 : break;
281 : case 2: // release()
282 0 : binuno_proxy_release( pUnoI );
283 0 : *ppException = 0; // no exc
284 0 : break;
285 : default:
286 0 : that->m_target.dispatch( pMemberType, pReturn, pArgs, ppException );
287 0 : break;
288 : }
289 0 : }
290 :
291 : }
292 :
293 :
294 0 : inline binuno_Proxy::binuno_Proxy(
295 : ::rtl::Reference< ProxyRoot > const & root,
296 : UnoInterfaceReference const & target,
297 : OUString const & oid, TypeDescription const & typeDescr )
298 : : m_nRefCount( 1 ),
299 : m_root( root ),
300 : m_target( target ),
301 : m_oid( oid ),
302 0 : m_typeDescr( typeDescr )
303 : {
304 0 : uno_Interface::acquire = binuno_proxy_acquire;
305 0 : uno_Interface::release = binuno_proxy_release;
306 0 : uno_Interface::pDispatcher = binuno_proxy_dispatch;
307 0 : }
308 :
309 :
310 0 : ProxyRoot::~ProxyRoot()
311 : {
312 0 : }
313 :
314 :
315 0 : inline ProxyRoot::ProxyRoot(
316 : ::rtl::Reference< FactoryImpl > const & factory,
317 : Reference< XInterface > const & xTarget )
318 0 : : m_factory( factory )
319 : {
320 0 : m_factory->m_cpp2uno.mapInterface(
321 0 : reinterpret_cast< void ** >( &m_target.m_pUnoI ), xTarget.get(),
322 0 : ::getCppuType( &xTarget ) );
323 : OSL_ENSURE( m_target.is(), "### mapping interface failed!" );
324 0 : }
325 :
326 :
327 0 : Any ProxyRoot::queryAggregation( Type const & rType )
328 : throw (RuntimeException, std::exception)
329 : {
330 0 : Any ret( OWeakAggObject::queryAggregation( rType ) );
331 0 : if (! ret.hasValue())
332 : {
333 0 : typelib_TypeDescription * pTypeDescr = 0;
334 0 : TYPELIB_DANGER_GET( &pTypeDescr, rType.getTypeLibType() );
335 : try
336 : {
337 0 : Reference< XInterface > xProxy;
338 0 : uno_ExtEnvironment * cpp_env = m_factory->m_cpp_env.get()->pExtEnv;
339 : OSL_ASSERT( cpp_env != 0 );
340 :
341 : // mind a new delegator, calculate current root:
342 : Reference< XInterface > xRoot(
343 0 : static_cast< OWeakObject * >(this), UNO_QUERY_THROW );
344 0 : OUString oid;
345 0 : (*cpp_env->getObjectIdentifier)( cpp_env, &oid.pData, xRoot.get() );
346 : OSL_ASSERT( !oid.isEmpty() );
347 :
348 : (*cpp_env->getRegisteredInterface)(
349 : cpp_env, reinterpret_cast< void ** >( &xProxy ),
350 : oid.pData, reinterpret_cast<
351 0 : typelib_InterfaceTypeDescription * >(pTypeDescr) );
352 0 : if (! xProxy.is())
353 : {
354 : // perform query on target:
355 : UnoInterfaceReference proxy_target(
356 : m_factory->binuno_queryInterface(
357 : m_target, reinterpret_cast<
358 0 : typelib_InterfaceTypeDescription * >(pTypeDescr) ) );
359 0 : if (proxy_target.is())
360 : {
361 : // ensure root's object entries:
362 0 : UnoInterfaceReference root;
363 0 : m_factory->m_cpp2uno.mapInterface(
364 : reinterpret_cast< void ** >( &root.m_pUnoI ),
365 0 : xRoot.get(), ::getCppuType( &xRoot ) );
366 :
367 : UnoInterfaceReference proxy(
368 : // ref count initially 1:
369 0 : new binuno_Proxy( this, proxy_target, oid, pTypeDescr ),
370 0 : SAL_NO_ACQUIRE );
371 : uno_ExtEnvironment * uno_env =
372 0 : m_factory->m_uno_env.get()->pExtEnv;
373 : OSL_ASSERT( uno_env != 0 );
374 : (*uno_env->registerProxyInterface)(
375 : uno_env, reinterpret_cast< void ** >( &proxy.m_pUnoI ),
376 : binuno_proxy_free, oid.pData,
377 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
378 0 : pTypeDescr ) );
379 :
380 0 : m_factory->m_uno2cpp.mapInterface(
381 : reinterpret_cast< void ** >( &xProxy ),
382 0 : proxy.get(), pTypeDescr );
383 0 : }
384 : }
385 0 : if (xProxy.is())
386 0 : ret.setValue( &xProxy, pTypeDescr );
387 : }
388 0 : catch (...) // finally
389 : {
390 0 : TYPELIB_DANGER_RELEASE( pTypeDescr );
391 0 : throw;
392 : }
393 0 : TYPELIB_DANGER_RELEASE( pTypeDescr );
394 : }
395 0 : return ret;
396 : }
397 :
398 :
399 :
400 :
401 0 : FactoryImpl::FactoryImpl()
402 : {
403 0 : OUString uno = UNO_LB_UNO;
404 0 : OUString cpp = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
405 :
406 : uno_getEnvironment(
407 0 : reinterpret_cast< uno_Environment ** >( &m_uno_env ), uno.pData, 0 );
408 : OSL_ENSURE( m_uno_env.is(), "### cannot get binary uno env!" );
409 :
410 : uno_getEnvironment(
411 0 : reinterpret_cast< uno_Environment ** >( &m_cpp_env ), cpp.pData, 0 );
412 : OSL_ENSURE( m_cpp_env.is(), "### cannot get C++ uno env!" );
413 :
414 : uno_getMapping(
415 : reinterpret_cast< uno_Mapping ** >( &m_uno2cpp ),
416 0 : m_uno_env.get(), m_cpp_env.get(), 0 );
417 : OSL_ENSURE( m_uno2cpp.is(), "### cannot get bridge uno <-> C++!" );
418 :
419 : uno_getMapping(
420 : reinterpret_cast< uno_Mapping ** >( &m_cpp2uno ),
421 0 : m_cpp_env.get(), m_uno_env.get(), 0 );
422 0 : OSL_ENSURE( m_cpp2uno.is(), "### cannot get bridge C++ <-> uno!" );
423 0 : }
424 :
425 :
426 0 : FactoryImpl::~FactoryImpl() {}
427 :
428 : // XProxyFactory
429 :
430 0 : Reference< XAggregation > FactoryImpl::createProxy(
431 : Reference< XInterface > const & xTarget )
432 : throw (RuntimeException, std::exception)
433 : {
434 0 : return new ProxyRoot( this, xTarget );
435 : }
436 :
437 : // XServiceInfo
438 :
439 0 : OUString FactoryImpl::getImplementationName()
440 : throw (RuntimeException, std::exception)
441 : {
442 0 : return proxyfac_getImplementationName();
443 : }
444 :
445 0 : sal_Bool FactoryImpl::supportsService( const OUString & rServiceName )
446 : throw (RuntimeException, std::exception)
447 : {
448 0 : return cppu::supportsService(this, rServiceName);
449 : }
450 :
451 0 : Sequence< OUString > FactoryImpl::getSupportedServiceNames()
452 : throw(::com::sun::star::uno::RuntimeException, std::exception)
453 : {
454 0 : return proxyfac_getSupportedServiceNames();
455 : }
456 :
457 :
458 0 : static Reference< XInterface > SAL_CALL proxyfac_create(
459 : SAL_UNUSED_PARAMETER Reference< XComponentContext > const & )
460 : throw (Exception)
461 : {
462 0 : Reference< XInterface > xRet;
463 : {
464 0 : ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() );
465 0 : static WeakReference < XInterface > rwInstance;
466 0 : xRet = rwInstance;
467 :
468 0 : if (! xRet.is())
469 : {
470 0 : xRet = static_cast< ::cppu::OWeakObject * >(new FactoryImpl);
471 0 : rwInstance = xRet;
472 0 : }
473 : }
474 0 : return xRet;
475 : }
476 :
477 : static const ::cppu::ImplementationEntry g_entries [] =
478 : {
479 : {
480 : proxyfac_create, proxyfac_getImplementationName,
481 : proxyfac_getSupportedServiceNames, ::cppu::createSingleComponentFactory,
482 : 0, 0
483 : },
484 : { 0, 0, 0, 0, 0, 0 }
485 : };
486 :
487 : }
488 :
489 0 : extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL proxyfac_component_getFactory(
490 : const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
491 : {
492 : return ::cppu::component_getFactoryHelper(
493 0 : pImplName, pServiceManager, pRegistryKey, g_entries );
494 : }
495 :
496 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|