xref: /trunk/main/cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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_cppu.hxx"
30 
31 #include "Proxy.hxx"
32 
33 #include "sal/alloca.h"
34 #include "uno/dispatcher.h"
35 #include "typelib/typedescription.hxx"
36 #include "cppu/EnvDcp.hxx"
37 
38 
39 //#define LOG_LIFECYCLE_Proxy
40 #ifdef LOG_LIFECYCLE_Proxy
41 #  include <iostream>
42 #  define LOG_LIFECYCLE_Proxy_emit(x) x
43 
44 #else
45 #  define LOG_LIFECYCLE_Proxy_emit(x)
46 
47 #endif
48 
49 
50 using namespace com::sun::star;
51 
52 
53 static bool relatesToInterface(typelib_TypeDescription * pTypeDescr)
54     SAL_THROW( () )
55 {
56     switch (pTypeDescr->eTypeClass)
57     {
58 //      case typelib_TypeClass_TYPEDEF:
59     case typelib_TypeClass_SEQUENCE:
60     {
61         switch (((typelib_IndirectTypeDescription *)pTypeDescr)->pType->eTypeClass)
62         {
63         case typelib_TypeClass_INTERFACE:
64         case typelib_TypeClass_UNION: // might relate to interface
65         case typelib_TypeClass_ANY: // might relate to interface
66             return true;
67         case typelib_TypeClass_SEQUENCE:
68         case typelib_TypeClass_STRUCT:
69         case typelib_TypeClass_EXCEPTION:
70         {
71             typelib_TypeDescription * pTD = 0;
72             TYPELIB_DANGER_GET( &pTD, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType );
73             bool bRel = relatesToInterface( pTD );
74             TYPELIB_DANGER_RELEASE( pTD );
75             return bRel;
76         }
77         default:
78             ;
79         }
80         return false;
81     }
82     case typelib_TypeClass_STRUCT:
83     case typelib_TypeClass_EXCEPTION:
84     {
85         // ...optimized... to avoid getDescription() calls!
86         typelib_CompoundTypeDescription * pComp    = (typelib_CompoundTypeDescription *)pTypeDescr;
87         typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs;
88         for ( sal_Int32 nPos = pComp->nMembers; nPos--; )
89         {
90             switch (pTypes[nPos]->eTypeClass)
91             {
92             case typelib_TypeClass_INTERFACE:
93             case typelib_TypeClass_UNION: // might relate to interface
94             case typelib_TypeClass_ANY: // might relate to interface
95                 return true;
96 //              case typelib_TypeClass_TYPEDEF:
97             case typelib_TypeClass_SEQUENCE:
98             case typelib_TypeClass_STRUCT:
99             case typelib_TypeClass_EXCEPTION:
100             {
101                 typelib_TypeDescription * pTD = 0;
102                 TYPELIB_DANGER_GET( &pTD, pTypes[nPos] );
103                 bool bRel = relatesToInterface( pTD );
104                 TYPELIB_DANGER_RELEASE( pTD );
105                 if (bRel)
106                     return true;
107             }
108             default:
109                 ;
110             }
111         }
112         if (pComp->pBaseTypeDescription)
113             return relatesToInterface( (typelib_TypeDescription *)pComp->pBaseTypeDescription );
114         break;
115     }
116     case typelib_TypeClass_UNION: // might relate to interface
117     case typelib_TypeClass_ANY: // might relate to interface
118     case typelib_TypeClass_INTERFACE:
119         return true;
120 
121     default:
122         ;
123     }
124     return false;
125 }
126 
127 extern "C" { static void SAL_CALL s_Proxy_dispatch(
128     uno_Interface                 * pUnoI,
129     typelib_TypeDescription const * pMemberType,
130     void                          * pReturn,
131     void                          * pArgs[],
132     uno_Any                      ** ppException)
133     SAL_THROW_EXTERN_C()
134 {
135     Proxy * pThis = static_cast<Proxy *>(pUnoI);
136 
137     typelib_MethodParameter            param;
138     sal_Int32                          nParams = 0;
139     typelib_MethodParameter          * pParams = 0;
140     typelib_TypeDescriptionReference * pReturnTypeRef = 0;
141     // sal_Int32                          nOutParams = 0;
142 
143     switch (pMemberType->eTypeClass)
144     {
145     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
146         if (pReturn)
147         {
148             pReturnTypeRef =
149                 ((typelib_InterfaceAttributeTypeDescription *)
150                  pMemberType)->pAttributeTypeRef;
151             nParams = 0;
152             pParams = NULL;
153         }
154         else
155         {
156             param.pTypeRef = ((typelib_InterfaceAttributeTypeDescription *)
157                               pMemberType)->pAttributeTypeRef;
158             param.bIn = sal_True;
159             param.bOut = sal_False;
160             nParams = 1;
161             pParams = &param;
162         }
163         break;
164     case typelib_TypeClass_INTERFACE_METHOD:
165     {
166         typelib_InterfaceMethodTypeDescription * method_td =
167             (typelib_InterfaceMethodTypeDescription *) pMemberType;
168         pReturnTypeRef = method_td->pReturnTypeRef;
169         nParams = method_td->nParams;
170         pParams = method_td->pParams;
171         break;
172     }
173     default:
174         OSL_ENSURE( sal_False, "### illegal member typeclass!" );
175         abort();
176     }
177 
178     pThis->dispatch( pReturnTypeRef,
179                      pParams,
180                      nParams,
181                      pMemberType,
182                      pReturn,
183                      pArgs,
184                      ppException );
185 }}
186 
187 extern "C" void SAL_CALL Proxy_free(uno_ExtEnvironment * /*pEnv*/, void * pProxy) SAL_THROW_EXTERN_C()
188 {
189     Proxy * pThis = static_cast<Proxy * >(reinterpret_cast<uno_Interface *>(pProxy));
190     delete pThis;
191 }
192 
193 extern "C" {
194 static void SAL_CALL s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
195 {
196     Proxy * pProxy = static_cast<Proxy *>(pUnoI);
197     pProxy->acquire();
198 }
199 
200 static void SAL_CALL s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
201 {
202     Proxy * pProxy = static_cast<Proxy *>(pUnoI);
203     pProxy->release();
204 }
205 
206 static void s_acquireAndRegister_v(va_list * pParam)
207 {
208     uno_Interface                    * pUnoI      = va_arg(*pParam, uno_Interface *);
209     rtl_uString                      * pOid       = va_arg(*pParam, rtl_uString *);
210     typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
211     uno_ExtEnvironment               * pEnv       = va_arg(*pParam, uno_ExtEnvironment *);
212 
213     pUnoI->acquire(pUnoI);
214     pEnv->registerInterface(pEnv, reinterpret_cast<void **>(&pUnoI), pOid, pTypeDescr);
215 }
216 }
217 
218 Proxy::Proxy(uno::Mapping                  const & to_from,
219              uno_Environment                     * pTo,
220              uno_Environment                     * pFrom,
221              uno_Interface                       * pUnoI,
222              typelib_InterfaceTypeDescription    * pTypeDescr,
223              rtl::OUString                 const & rOId,
224              cppu::helper::purpenv::ProbeFun     * probeFun,
225              void                                * pProbeContext
226 )
227     SAL_THROW(())
228         : m_nRef         (1),
229           m_from         (pFrom),
230           m_to           (pTo),
231           m_from_to      (pFrom, pTo),
232           m_to_from      (to_from),
233           m_pUnoI        (pUnoI),
234           m_pTypeDescr   (pTypeDescr),
235           m_aOId         (rOId),
236           m_probeFun     (probeFun),
237           m_pProbeContext(pProbeContext)
238 {
239     LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::Proxy(<>)", this));
240 
241     typelib_typedescription_acquire((typelib_TypeDescription *)m_pTypeDescr);
242     if (!((typelib_TypeDescription *)m_pTypeDescr)->bComplete)
243         typelib_typedescription_complete((typelib_TypeDescription **)&m_pTypeDescr);
244 
245     OSL_ENSURE(((typelib_TypeDescription *)m_pTypeDescr)->bComplete, "### type is incomplete!");
246 
247     uno_Environment_invoke(m_to.get(), s_acquireAndRegister_v, m_pUnoI, rOId.pData, pTypeDescr, m_to.get());
248 
249     // uno_Interface
250     uno_Interface::acquire     = s_Proxy_acquire;
251     uno_Interface::release     = s_Proxy_release;
252     uno_Interface::pDispatcher = s_Proxy_dispatch;
253 }
254 
255 extern "C" { static void s_releaseAndRevoke_v(va_list * pParam)
256 {
257     uno_ExtEnvironment * pEnv  = va_arg(*pParam, uno_ExtEnvironment *);
258     uno_Interface      * pUnoI = va_arg(*pParam, uno_Interface *);
259 
260     pEnv->revokeInterface(pEnv, reinterpret_cast<void *>(pUnoI));
261     pUnoI->release(pUnoI);
262 }}
263 
264 Proxy::~Proxy()
265 {
266     LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::~Proxy()", this));
267 
268     uno_Environment_invoke(m_to.get(), s_releaseAndRevoke_v, m_to.get(), m_pUnoI);
269 
270     typelib_typedescription_release((typelib_TypeDescription *)m_pTypeDescr);
271 }
272 
273 static uno::TypeDescription getAcquireMethod(void)
274 {
275     typelib_TypeDescriptionReference * type_XInterface =
276         * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
277 
278     typelib_TypeDescription * pTXInterfaceDescr = 0;
279     TYPELIB_DANGER_GET    (&pTXInterfaceDescr, type_XInterface);
280     uno::TypeDescription acquire(
281         reinterpret_cast< typelib_InterfaceTypeDescription * >(
282             pTXInterfaceDescr)->ppAllMembers[1]);
283     TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
284 
285     return acquire;
286 }
287 
288 static uno::TypeDescription getReleaseMethod(void)
289 {
290     typelib_TypeDescriptionReference * type_XInterface =
291         * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
292 
293     typelib_TypeDescription * pTXInterfaceDescr = 0;
294     TYPELIB_DANGER_GET    (&pTXInterfaceDescr, type_XInterface);
295     uno::TypeDescription release(
296         reinterpret_cast< typelib_InterfaceTypeDescription * >(
297             pTXInterfaceDescr)->ppAllMembers[2]);
298     TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
299 
300     return release;
301 }
302 
303 static uno::TypeDescription s_acquireMethod(getAcquireMethod());
304 static uno::TypeDescription s_releaseMethod(getReleaseMethod());
305 
306 void Proxy::acquire(void)
307 {
308     if (m_probeFun)
309         m_probeFun(true,
310                    this,
311                    m_pProbeContext,
312                    *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
313                    NULL,
314                    0,
315                    s_acquireMethod.get(),
316                    NULL,
317                    NULL,
318                    NULL);
319 
320     if (osl_incrementInterlockedCount(&m_nRef) == 1)
321     {
322         // rebirth of proxy zombie
323         void * pThis = this;
324         m_from.get()->pExtEnv->registerProxyInterface(m_from.get()->pExtEnv,
325                                                       &pThis,
326                                                       Proxy_free,
327                                                       m_aOId.pData,
328                                                       m_pTypeDescr);
329         OSL_ASSERT(pThis == this);
330     }
331 
332     if (m_probeFun)
333         m_probeFun(false,
334                    this,
335                    m_pProbeContext,
336                    *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
337                    NULL,
338                    0,
339                    s_acquireMethod.get(),
340                    NULL,
341                    NULL,
342                    NULL);
343 
344 }
345 
346 void Proxy::release(void)
347 {
348     cppu::helper::purpenv::ProbeFun * probeFun = m_probeFun;
349     void                            * pProbeContext = m_pProbeContext;
350 
351     if (m_probeFun)
352         m_probeFun(true,
353                    this,
354                    m_pProbeContext,
355                    *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
356                    NULL,
357                    0,
358                    s_releaseMethod.get(),
359                    NULL,
360                    NULL,
361                    NULL);
362 
363     if (osl_decrementInterlockedCount(&m_nRef) == 0)
364         m_from.get()->pExtEnv->revokeInterface(m_from.get()->pExtEnv, this);
365 
366     if (probeFun)
367         probeFun(false,
368                  this,
369                  pProbeContext,
370                  *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
371                  NULL,
372                  0,
373                  s_releaseMethod.get(),
374                  NULL,
375                  NULL,
376                  NULL);
377 
378 }
379 
380 
381 extern "C" {
382 static void s_type_destructData_v(va_list * pParam)
383 {
384     void * ret = va_arg(*pParam, void *);
385     typelib_TypeDescriptionReference * pReturnTypeRef = va_arg(*pParam, typelib_TypeDescriptionReference *);
386 
387     uno_type_destructData(ret, pReturnTypeRef, 0);
388 }
389 
390 static void s_dispatcher_v(va_list * pParam)
391 {
392     uno_Interface                 * pUnoI       = va_arg(*pParam, uno_Interface *);
393     typelib_TypeDescription const * pMemberType = va_arg(*pParam, typelib_TypeDescription const *);
394     void                          * pReturn     = va_arg(*pParam, void *);
395     void                         ** pArgs       = va_arg(*pParam, void **);
396     uno_Any                      ** ppException = va_arg(*pParam, uno_Any **);
397 
398     pUnoI->pDispatcher(pUnoI, pMemberType, pReturn, pArgs, ppException);
399 }
400 }
401 
402 void Proxy::dispatch(typelib_TypeDescriptionReference * pReturnTypeRef,
403                      typelib_MethodParameter          * pParams,
404                      sal_Int32                          nParams,
405                      typelib_TypeDescription    const * pMemberType,
406                      void                             * pReturn,
407                      void                             * pArgs[],
408                      uno_Any                         ** ppException)
409 {
410     if (m_probeFun)
411         m_probeFun(true,
412                    this,
413                    m_pProbeContext,
414                    pReturnTypeRef,
415                    pParams,
416                    nParams,
417                    pMemberType,
418                    pReturn,
419                    pArgs,
420                    ppException);
421 
422     void ** args = (void **) alloca( sizeof (void *) * nParams );
423 
424     typelib_TypeDescription * return_td = 0;
425     void * ret = pReturn;
426     if (pReturnTypeRef)
427     {
428         TYPELIB_DANGER_GET(&return_td, pReturnTypeRef);
429 
430         if (relatesToInterface(return_td))
431             ret = alloca(return_td->nSize);
432 
433         TYPELIB_DANGER_RELEASE(return_td);
434     }
435 
436     for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
437     {
438         typelib_MethodParameter const & param = pParams[nPos];
439         typelib_TypeDescription * td = 0;
440         TYPELIB_DANGER_GET( &td, param.pTypeRef );
441         if (relatesToInterface(td))
442         {
443             args[nPos] = alloca(td->nSize);
444             if (param.bIn)
445             {
446                 uno_copyAndConvertData(args[nPos], pArgs[nPos], td, m_from_to.get());
447             }
448         }
449         else
450         {
451             args[nPos] = pArgs[nPos];
452         }
453         TYPELIB_DANGER_RELEASE( td );
454     }
455 
456     uno_Any exc_data;
457     uno_Any * exc = &exc_data;
458 
459     // do the UNO call...
460     uno_Environment_invoke(m_to.get(), s_dispatcher_v, m_pUnoI, pMemberType, ret, args, &exc);
461 
462     if (exc == 0)
463     {
464         for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
465         {
466             if (args[nPos] != pArgs[nPos])
467             {
468                 typelib_MethodParameter const & param = pParams[nPos];
469                 if (param.bOut)
470                 {
471                     if (param.bIn) // is inout
472                     {
473                         uno_type_destructData(pArgs[nPos], param.pTypeRef, 0);
474                     }
475                     uno_type_copyAndConvertData(pArgs[ nPos ],
476                                                 args[ nPos ],
477                                                 param.pTypeRef,
478                                                 m_to_from.get());
479                 }
480                 uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
481             }
482         }
483         if (ret != pReturn)
484         {
485             uno_type_copyAndConvertData(pReturn,
486                                         ret,
487                                         pReturnTypeRef,
488                                         m_to_from.get());
489 
490             uno_Environment_invoke(m_to.get(), s_type_destructData_v, ret, pReturnTypeRef, 0);
491         }
492 
493         *ppException = 0;
494     }
495     else // exception occured
496     {
497         for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
498         {
499             if (args[nPos] != pArgs[nPos])
500             {
501                 typelib_MethodParameter const & param = pParams[nPos];
502                 if (param.bIn)
503                 {
504                     uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
505                 }
506             }
507         }
508 
509         uno_type_any_constructAndConvert(*ppException,
510                                          exc->pData,
511                                          exc->pType,
512                                          m_to_from.get());
513 
514         // FIXME: need to destruct in m_to
515         uno_any_destruct(exc, 0);
516     }
517 
518     if (m_probeFun)
519         m_probeFun(false,
520                    this,
521                    m_pProbeContext,
522                    pReturnTypeRef,
523                    pParams,
524                    nParams,
525                    pMemberType,
526                    pReturn,
527                    pArgs,
528                    ppException);
529 }
530 
531