1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_bridges.hxx"
26 
27 #include <sal/alloca.h>
28 
29 #include "com/sun/star/uno/RuntimeException.hpp"
30 
31 #include "rtl/ustrbuf.hxx"
32 
33 #include "jni_bridge.h"
34 
35 
36 using namespace ::std;
37 using namespace ::rtl;
38 
39 namespace
40 {
41 extern "C"
42 {
43 
44 //------------------------------------------------------------------------------
45 void SAL_CALL UNO_proxy_free( uno_ExtEnvironment * env, void * proxy )
46     SAL_THROW_EXTERN_C();
47 
48 //------------------------------------------------------------------------------
49 void SAL_CALL UNO_proxy_acquire( uno_Interface * pUnoI )
50     SAL_THROW_EXTERN_C();
51 
52 //------------------------------------------------------------------------------
53 void SAL_CALL UNO_proxy_release( uno_Interface * pUnoI )
54     SAL_THROW_EXTERN_C();
55 
56 //------------------------------------------------------------------------------
57 void SAL_CALL UNO_proxy_dispatch(
58     uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
59     void * uno_ret, void * uno_args[], uno_Any ** uno_exc )
60     SAL_THROW_EXTERN_C();
61 }
62 }
63 
64 namespace jni_uno
65 {
66 
67 //______________________________________________________________________________
handle_java_exc(JNI_context const & jni,JLocalAutoRef const & jo_exc,uno_Any * uno_exc) const68 void Bridge::handle_java_exc(
69     JNI_context const & jni,
70     JLocalAutoRef const & jo_exc, uno_Any * uno_exc ) const
71 {
72     OSL_ASSERT( jo_exc.is() );
73     if (! jo_exc.is())
74     {
75         throw BridgeRuntimeError(
76             OUSTR("java exception occured, but no java exception available!?") +
77             jni.get_stack_trace() );
78     }
79 
80     JLocalAutoRef jo_class( jni, jni->GetObjectClass( jo_exc.get() ) );
81     JLocalAutoRef jo_class_name(
82         jni, jni->CallObjectMethodA(
83             jo_class.get(), m_jni_info->m_method_Class_getName, 0 ) );
84     jni.ensure_no_exception();
85     OUString exc_name(
86         jstring_to_oustring( jni, (jstring) jo_class_name.get() ) );
87 
88     ::com::sun::star::uno::TypeDescription td( exc_name.pData );
89     if (!td.is() || (typelib_TypeClass_EXCEPTION != td.get()->eTypeClass))
90     {
91         // call toString()
92         JLocalAutoRef jo_descr(
93             jni, jni->CallObjectMethodA(
94                 jo_exc.get(), m_jni_info->m_method_Object_toString, 0 ) );
95         jni.ensure_no_exception();
96         OUStringBuffer buf( 128 );
97         buf.appendAscii(
98             RTL_CONSTASCII_STRINGPARAM("non-UNO exception occurred: ") );
99         buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) );
100         buf.append( jni.get_stack_trace( jo_exc.get() ) );
101         throw BridgeRuntimeError( buf.makeStringAndClear() );
102     }
103 
104     auto_ptr< rtl_mem > uno_data( rtl_mem::allocate( td.get()->nSize ) );
105     jvalue val;
106     val.l = jo_exc.get();
107     map_to_uno(
108         jni, uno_data.get(), val, td.get()->pWeakRef, 0,
109         false /* no assign */, false /* no out param */ );
110 
111 #if OSL_DEBUG_LEVEL > 0
112     // patch Message, append stack trace
113     reinterpret_cast< ::com::sun::star::uno::Exception * >(
114         uno_data.get() )->Message += jni.get_stack_trace( jo_exc.get() );
115 #endif
116 
117     typelib_typedescriptionreference_acquire( td.get()->pWeakRef );
118     uno_exc->pType = td.get()->pWeakRef;
119     uno_exc->pData = uno_data.release();
120 
121 #if OSL_DEBUG_LEVEL > 1
122     OUStringBuffer trace_buf( 128 );
123     trace_buf.appendAscii(
124         RTL_CONSTASCII_STRINGPARAM("exception occured uno->java: [") );
125     trace_buf.append( exc_name );
126     trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] ") );
127     trace_buf.append(
128         reinterpret_cast< ::com::sun::star::uno::Exception const * >(
129             uno_exc->pData )->Message );
130     OString cstr_trace(
131         OUStringToOString(
132             trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
133     OSL_TRACE( cstr_trace.getStr() );
134 #endif
135 }
136 
137 //______________________________________________________________________________
call_java(jobject javaI,typelib_InterfaceTypeDescription * iface_td,sal_Int32 local_member_index,sal_Int32 function_pos_offset,typelib_TypeDescriptionReference * return_type,typelib_MethodParameter * params,sal_Int32 nParams,void * uno_ret,void * uno_args[],uno_Any ** uno_exc) const138 void Bridge::call_java(
139     jobject javaI, typelib_InterfaceTypeDescription * iface_td,
140     sal_Int32 local_member_index, sal_Int32 function_pos_offset,
141     typelib_TypeDescriptionReference * return_type,
142     typelib_MethodParameter * params, sal_Int32 nParams,
143     void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const
144 {
145     OSL_ASSERT( function_pos_offset == 0 || function_pos_offset == 1 );
146 
147     JNI_guarded_context jni(
148         m_jni_info, reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
149             m_java_env->pContext ) );
150 
151     // assure fully initialized iface_td:
152     ::com::sun::star::uno::TypeDescription iface_holder;
153     if (! iface_td->aBase.bComplete) {
154         iface_holder = ::com::sun::star::uno::TypeDescription(
155             reinterpret_cast<typelib_TypeDescription *>(iface_td) );
156         iface_holder.makeComplete();
157         if (! iface_holder.get()->bComplete) {
158             OUStringBuffer buf;
159             buf.appendAscii(
160                 RTL_CONSTASCII_STRINGPARAM("cannot make type complete: ") );
161             buf.append( OUString::unacquired(&iface_holder.get()->pTypeName) );
162             buf.append( jni.get_stack_trace() );
163             throw BridgeRuntimeError( buf.makeStringAndClear() );
164         }
165         iface_td = reinterpret_cast<typelib_InterfaceTypeDescription *>(
166             iface_holder.get() );
167         OSL_ASSERT( iface_td->aBase.eTypeClass == typelib_TypeClass_INTERFACE );
168     }
169 
170     // prepare java args, save param td
171 #ifdef BROKEN_ALLOCA
172     jvalue * java_args = (jvalue *) malloc( sizeof (jvalue) * nParams );
173 #else
174     jvalue * java_args = (jvalue *) alloca( sizeof (jvalue) * nParams );
175 #endif
176 
177     sal_Int32 nPos;
178     for ( nPos = 0; nPos < nParams; ++nPos )
179     {
180         try
181         {
182             typelib_MethodParameter const & param = params[ nPos ];
183             java_args[ nPos ].l = 0; // if out: build up array[ 1 ]
184             map_to_java(
185                 jni, &java_args[ nPos ],
186                 uno_args[ nPos ],
187                 param.pTypeRef, 0,
188                 sal_False != param.bIn /* convert uno value */,
189                 sal_False != param.bOut /* build up array[ 1 ] */ );
190         }
191         catch (...)
192         {
193             // cleanup
194             for ( sal_Int32 n = 0; n < nPos; ++n )
195             {
196                 typelib_MethodParameter const & param = params[ n ];
197                 if (param.bOut ||
198                     typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
199                 {
200                     jni->DeleteLocalRef( java_args[ n ].l );
201                 }
202             }
203 #ifdef BROKEN_ALLOCA
204 	    free( java_args );
205 #endif
206             throw;
207         }
208     }
209 
210     sal_Int32 base_members = iface_td->nAllMembers - iface_td->nMembers;
211     OSL_ASSERT( base_members < iface_td->nAllMembers );
212     sal_Int32 base_members_function_pos =
213         iface_td->pMapMemberIndexToFunctionIndex[ base_members ];
214     sal_Int32 member_pos = base_members + local_member_index;
215     OSL_ENSURE(
216         member_pos < iface_td->nAllMembers, "### member pos out of range!" );
217     sal_Int32 function_pos =
218         iface_td->pMapMemberIndexToFunctionIndex[ member_pos ]
219         + function_pos_offset;
220     OSL_ENSURE(
221         function_pos >= base_members_function_pos
222         && function_pos < iface_td->nMapFunctionIndexToMemberIndex,
223         "### illegal function index!" );
224     function_pos -= base_members_function_pos;
225 
226     JNI_interface_type_info const * info =
227         static_cast< JNI_interface_type_info const * >(
228             m_jni_info->get_type_info( jni, &iface_td->aBase ) );
229     jmethodID method_id = info->m_methods[ function_pos ];
230 
231 #if OSL_DEBUG_LEVEL > 1
232     OUStringBuffer trace_buf( 128 );
233     trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("calling ") );
234     JLocalAutoRef jo_method(
235         jni, jni->ToReflectedMethod( info->m_class, method_id, JNI_FALSE ) );
236     jni.ensure_no_exception();
237     JLocalAutoRef jo_descr(
238         jni, jni->CallObjectMethodA(
239             jo_method.get(), m_jni_info->m_method_Object_toString, 0 ) );
240     jni.ensure_no_exception();
241     trace_buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) );
242     trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" on ") );
243     jo_descr.reset(
244         jni->CallObjectMethodA(
245             javaI, m_jni_info->m_method_Object_toString, 0 ) );
246     jni.ensure_no_exception();
247     trace_buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) );
248     trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" (") );
249     JLocalAutoRef jo_class( jni, jni->GetObjectClass( javaI ) );
250     jo_descr.reset(
251         jni->CallObjectMethodA(
252             jo_class.get(), m_jni_info->m_method_Object_toString, 0 ) );
253     jni.ensure_no_exception();
254     trace_buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) );
255     trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(")") );
256     OString cstr_trace(
257         OUStringToOString(
258             trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
259     OSL_TRACE( cstr_trace.getStr() );
260 #endif
261 
262     // complex return value
263     JLocalAutoRef java_ret( jni );
264 
265     switch (return_type->eTypeClass)
266     {
267     case typelib_TypeClass_VOID:
268         jni->CallVoidMethodA( javaI, method_id, java_args );
269         break;
270     case typelib_TypeClass_CHAR:
271         *(sal_Unicode *)uno_ret =
272             jni->CallCharMethodA( javaI, method_id, java_args );
273         break;
274     case typelib_TypeClass_BOOLEAN:
275         *(sal_Bool *)uno_ret =
276             jni->CallBooleanMethodA( javaI, method_id, java_args );
277         break;
278     case typelib_TypeClass_BYTE:
279         *(sal_Int8 *)uno_ret =
280             jni->CallByteMethodA( javaI, method_id, java_args );
281         break;
282     case typelib_TypeClass_SHORT:
283     case typelib_TypeClass_UNSIGNED_SHORT:
284         *(sal_Int16 *)uno_ret =
285             jni->CallShortMethodA( javaI, method_id, java_args );
286         break;
287     case typelib_TypeClass_LONG:
288     case typelib_TypeClass_UNSIGNED_LONG:
289         *(sal_Int32 *)uno_ret =
290             jni->CallIntMethodA( javaI, method_id, java_args );
291         break;
292     case typelib_TypeClass_HYPER:
293     case typelib_TypeClass_UNSIGNED_HYPER:
294         *(sal_Int64 *)uno_ret =
295             jni->CallLongMethodA( javaI, method_id, java_args );
296         break;
297     case typelib_TypeClass_FLOAT:
298         *(float *)uno_ret =
299             jni->CallFloatMethodA( javaI, method_id, java_args );
300         break;
301     case typelib_TypeClass_DOUBLE:
302         *(double *)uno_ret =
303             jni->CallDoubleMethodA( javaI, method_id, java_args );
304         break;
305     default:
306         java_ret.reset(
307             jni->CallObjectMethodA( javaI, method_id, java_args ) );
308         break;
309     }
310 
311     if (jni->ExceptionCheck())
312     {
313         JLocalAutoRef jo_exc( jni, jni->ExceptionOccurred() );
314         jni->ExceptionClear();
315 
316         // release temp java local refs
317         for ( nPos = 0; nPos < nParams; ++nPos )
318         {
319             typelib_MethodParameter const & param = params[ nPos ];
320             if (param.bOut ||
321                 typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
322             {
323                 jni->DeleteLocalRef( java_args[ nPos ].l );
324             }
325         }
326 
327         handle_java_exc( jni, jo_exc, *uno_exc );
328     }
329     else // no exception
330     {
331         for ( nPos = 0; nPos < nParams; ++nPos )
332         {
333             typelib_MethodParameter const & param = params[ nPos ];
334             if (param.bOut)
335             {
336                 try
337                 {
338                     map_to_uno(
339                         jni, uno_args[ nPos ],
340                         java_args[ nPos ], param.pTypeRef, 0,
341                         sal_False != param.bIn /* assign if inout */,
342                         true /* out param */ );
343                 }
344                 catch (...)
345                 {
346                     // cleanup uno pure out
347                     for ( sal_Int32 n = 0; n < nPos; ++n )
348                     {
349                         typelib_MethodParameter const & p = params[ n ];
350                         if (! p.bIn)
351                         {
352                             uno_type_destructData(
353                                 uno_args[ n ], p.pTypeRef, 0 );
354                         }
355                     }
356                     // cleanup java temp local refs
357                     for ( ; nPos < nParams; ++nPos )
358                     {
359                         typelib_MethodParameter const & p = params[ nPos ];
360                         if (p.bOut ||
361                             typelib_TypeClass_DOUBLE <
362                               p.pTypeRef->eTypeClass)
363                         {
364                             jni->DeleteLocalRef( java_args[ nPos ].l );
365                         }
366                     }
367 #ifdef BROKEN_ALLOCA
368 		    free( java_args );
369 #endif
370                     throw;
371                 }
372                 jni->DeleteLocalRef( java_args[ nPos ].l );
373             }
374             else // pure temp in param
375             {
376                 if (typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass)
377                     jni->DeleteLocalRef( java_args[ nPos ].l );
378             }
379         }
380 
381         // return value
382         if (typelib_TypeClass_DOUBLE < return_type->eTypeClass)
383         {
384             try
385             {
386                 jvalue val;
387                 val.l = java_ret.get();
388                 map_to_uno(
389                     jni, uno_ret, val, return_type, 0,
390                     false /* no assign */, false /* no out param */ );
391             }
392             catch (...)
393             {
394                 // cleanup uno pure out
395                 for ( sal_Int32 i = 0; i < nParams; ++i )
396                 {
397                     typelib_MethodParameter const & param = params[ i ];
398                     if (! param.bIn)
399                     {
400                         uno_type_destructData(
401                             uno_args[ i ], param.pTypeRef, 0 );
402                     }
403                 }
404 #ifdef BROKEN_ALLOCA
405 		free( java_args );
406 #endif
407                 throw;
408             }
409         } // else: already set integral uno return value
410 
411         // no exception occured
412         *uno_exc = 0;
413     }
414 #ifdef BROKEN_ALLOCA
415     free( java_args );
416 #endif
417 }
418 
419 //==== a uno proxy wrapping a java interface ===================================
420 struct UNO_proxy : public uno_Interface
421 {
422     mutable oslInterlockedCount         m_ref;
423     Bridge const *                      m_bridge;
424 
425     // mapping information
426     jobject                             m_javaI;
427     jstring                             m_jo_oid;
428     OUString                            m_oid;
429     JNI_interface_type_info const *     m_type_info;
430 
431     inline void acquire() const;
432     inline void release() const;
433 
434     // ctor
435     inline UNO_proxy(
436         JNI_context const & jni, Bridge const * bridge,
437         jobject javaI, jstring jo_oid, OUString const & oid,
438         JNI_interface_type_info const * info );
439 };
440 
441 //______________________________________________________________________________
UNO_proxy(JNI_context const & jni,Bridge const * bridge,jobject javaI,jstring jo_oid,OUString const & oid,JNI_interface_type_info const * info)442 inline UNO_proxy::UNO_proxy(
443     JNI_context const & jni, Bridge const * bridge,
444     jobject javaI, jstring jo_oid, OUString const & oid,
445     JNI_interface_type_info const * info )
446     : m_ref( 1 ),
447       m_oid( oid ),
448       m_type_info( info )
449 {
450     JNI_info const * jni_info = bridge->m_jni_info;
451     JLocalAutoRef jo_string_array(
452         jni, jni->NewObjectArray( 1, jni_info->m_class_String, jo_oid ) );
453     jni.ensure_no_exception();
454     jvalue args[ 3 ];
455     args[ 0 ].l = javaI;
456     args[ 1 ].l = jo_string_array.get();
457     args[ 2 ].l = info->m_type;
458     jobject jo_iface = jni->CallObjectMethodA(
459         jni_info->m_object_java_env,
460         jni_info->m_method_IEnvironment_registerInterface, args );
461     jni.ensure_no_exception();
462 
463     m_javaI = jni->NewGlobalRef( jo_iface );
464     m_jo_oid = (jstring) jni->NewGlobalRef( jo_oid );
465     bridge->acquire();
466     m_bridge = bridge;
467 
468     // uno_Interface
469     uno_Interface::acquire = UNO_proxy_acquire;
470     uno_Interface::release = UNO_proxy_release;
471     uno_Interface::pDispatcher = UNO_proxy_dispatch;
472 }
473 
474 //______________________________________________________________________________
acquire() const475 inline void UNO_proxy::acquire() const
476 {
477     if (1 == osl_incrementInterlockedCount( &m_ref ))
478     {
479         // rebirth of proxy zombie
480         void * that = const_cast< UNO_proxy * >( this );
481         // register at uno env
482         (*m_bridge->m_uno_env->registerProxyInterface)(
483             m_bridge->m_uno_env, &that,
484             UNO_proxy_free, m_oid.pData,
485             (typelib_InterfaceTypeDescription *)m_type_info->m_td.get() );
486 #if OSL_DEBUG_LEVEL > 1
487         OSL_ASSERT( this == (void const * const)that );
488 #endif
489     }
490 }
491 
492 //______________________________________________________________________________
release() const493 inline void UNO_proxy::release() const
494 {
495     if (0 == osl_decrementInterlockedCount( &m_ref ))
496     {
497         // revoke from uno env on last release
498         (*m_bridge->m_uno_env->revokeInterface)(
499             m_bridge->m_uno_env, const_cast< UNO_proxy * >( this ) );
500     }
501 }
502 
503 
504 //______________________________________________________________________________
map_to_uno(JNI_context const & jni,jobject javaI,JNI_interface_type_info const * info) const505 uno_Interface * Bridge::map_to_uno(
506     JNI_context const & jni,
507     jobject javaI, JNI_interface_type_info const * info ) const
508 {
509     JLocalAutoRef jo_oid( jni, compute_oid( jni, javaI ) );
510     OUString oid( jstring_to_oustring( jni, (jstring) jo_oid.get() ) );
511 
512     uno_Interface * pUnoI = 0;
513     (*m_uno_env->getRegisteredInterface)(
514         m_uno_env, (void **)&pUnoI,
515         oid.pData, (typelib_InterfaceTypeDescription *)info->m_td.get() );
516 
517     if (0 == pUnoI) // no existing interface, register new proxy
518     {
519         // refcount initially 1
520         pUnoI = new UNO_proxy(
521             jni, const_cast< Bridge * >( this ),
522             javaI, (jstring) jo_oid.get(), oid, info );
523 
524         (*m_uno_env->registerProxyInterface)(
525             m_uno_env, (void **)&pUnoI,
526             UNO_proxy_free,
527             oid.pData, (typelib_InterfaceTypeDescription *)info->m_td.get() );
528     }
529     return pUnoI;
530 }
531 
532 }
533 
534 using namespace ::jni_uno;
535 
536 namespace
537 {
538 extern "C"
539 {
540 
541 //------------------------------------------------------------------------------
UNO_proxy_free(uno_ExtEnvironment * env,void * proxy)542 void SAL_CALL UNO_proxy_free( uno_ExtEnvironment * env, void * proxy )
543     SAL_THROW_EXTERN_C()
544 {
545     UNO_proxy const * that = reinterpret_cast< UNO_proxy const * >( proxy );
546     Bridge const * bridge = that->m_bridge;
547 
548     if ( env != bridge->m_uno_env ) {
549         OSL_ASSERT(false);
550     }
551 #if OSL_DEBUG_LEVEL > 1
552     OString cstr_msg(
553         OUStringToOString(
554             OUSTR("freeing binary uno proxy: ") + that->m_oid,
555             RTL_TEXTENCODING_ASCII_US ) );
556     OSL_TRACE( cstr_msg.getStr() );
557 #endif
558 
559     try
560     {
561         JNI_guarded_context jni(
562             bridge->m_jni_info,
563             reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
564                 bridge->m_java_env->pContext ) );
565 
566         jni->DeleteGlobalRef( that->m_javaI );
567         jni->DeleteGlobalRef( that->m_jo_oid );
568     }
569     catch (BridgeRuntimeError & err)
570     {
571 #if OSL_DEBUG_LEVEL > 0
572         OString cstr_msg2(
573             OUStringToOString( err.m_message, RTL_TEXTENCODING_ASCII_US ) );
574         OSL_ENSURE( 0, cstr_msg2.getStr() );
575 #else
576         (void) err; // unused
577 #endif
578     }
579     catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
580     {
581         OSL_ENSURE(
582             0,
583             "[jni_uno bridge error] attaching current thread to java failed!" );
584     }
585 
586     bridge->release();
587 #if OSL_DEBUG_LEVEL > 1
588     *(int *)that = 0xdeadcafe;
589 #endif
590     delete that;
591 }
592 
593 //------------------------------------------------------------------------------
UNO_proxy_acquire(uno_Interface * pUnoI)594 void SAL_CALL UNO_proxy_acquire( uno_Interface * pUnoI )
595     SAL_THROW_EXTERN_C()
596 {
597     UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
598     that->acquire();
599 }
600 
601 //------------------------------------------------------------------------------
UNO_proxy_release(uno_Interface * pUnoI)602 void SAL_CALL UNO_proxy_release( uno_Interface * pUnoI )
603     SAL_THROW_EXTERN_C()
604 {
605     UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
606     that->release();
607 }
608 
609 //------------------------------------------------------------------------------
UNO_proxy_dispatch(uno_Interface * pUnoI,typelib_TypeDescription const * member_td,void * uno_ret,void * uno_args[],uno_Any ** uno_exc)610 void SAL_CALL UNO_proxy_dispatch(
611     uno_Interface * pUnoI, typelib_TypeDescription const * member_td,
612     void * uno_ret, void * uno_args [], uno_Any ** uno_exc )
613     SAL_THROW_EXTERN_C()
614 {
615     UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI );
616     Bridge const * bridge = that->m_bridge;
617 
618 #if OSL_DEBUG_LEVEL > 1
619     OUStringBuffer trace_buf( 64 );
620     trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("uno->java call: ") );
621     trace_buf.append( OUString::unacquired( &member_td->pTypeName ) );
622     trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" on oid ") );
623     trace_buf.append( that->m_oid );
624     OString cstr_msg(
625         OUStringToOString(
626             trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
627     OSL_TRACE( cstr_msg.getStr() );
628 #endif
629 
630     try
631     {
632         switch (member_td->eTypeClass)
633         {
634         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
635         {
636             typelib_InterfaceAttributeTypeDescription const * attrib_td =
637                 reinterpret_cast<
638                 typelib_InterfaceAttributeTypeDescription const * >(
639                     member_td );
640             com::sun::star::uno::TypeDescription attrib_holder;
641             while ( attrib_td->pBaseRef != 0 ) {
642                 attrib_holder = com::sun::star::uno::TypeDescription(
643                     attrib_td->pBaseRef );
644                 OSL_ASSERT(
645                     attrib_holder.get()->eTypeClass
646                     == typelib_TypeClass_INTERFACE_ATTRIBUTE );
647                 attrib_td = reinterpret_cast<
648                     typelib_InterfaceAttributeTypeDescription * >(
649                         attrib_holder.get() );
650             }
651             typelib_InterfaceTypeDescription * iface_td = attrib_td->pInterface;
652 
653             if (0 == uno_ret) // is setter method
654             {
655                 typelib_MethodParameter param;
656                 param.pTypeRef = attrib_td->pAttributeTypeRef;
657                 param.bIn = sal_True;
658                 param.bOut = sal_False;
659 
660                 bridge->call_java(
661                     that->m_javaI, iface_td,
662                     attrib_td->nIndex, 1, // get, then set method
663                     bridge->m_jni_info->m_void_type.getTypeLibType(),
664                     &param, 1,
665                     0, uno_args, uno_exc );
666             }
667             else // is getter method
668             {
669                 bridge->call_java(
670                     that->m_javaI, iface_td, attrib_td->nIndex, 0,
671                     attrib_td->pAttributeTypeRef,
672                     0, 0, // no params
673                     uno_ret, 0, uno_exc );
674             }
675             break;
676         }
677         case typelib_TypeClass_INTERFACE_METHOD:
678         {
679             typelib_InterfaceMethodTypeDescription const * method_td =
680                 reinterpret_cast<
681                 typelib_InterfaceMethodTypeDescription const * >(
682                     member_td );
683             com::sun::star::uno::TypeDescription method_holder;
684             while ( method_td->pBaseRef != 0 ) {
685                 method_holder = com::sun::star::uno::TypeDescription(
686                     method_td->pBaseRef );
687                 OSL_ASSERT(
688                     method_holder.get()->eTypeClass
689                     == typelib_TypeClass_INTERFACE_METHOD );
690                 method_td = reinterpret_cast<
691                     typelib_InterfaceMethodTypeDescription * >(
692                         method_holder.get() );
693             }
694             typelib_InterfaceTypeDescription * iface_td = method_td->pInterface;
695 
696             switch ( method_td->aBase.nPosition )
697             {
698             case 0: // queryInterface()
699             {
700                 TypeDescr demanded_td(
701                     *reinterpret_cast< typelib_TypeDescriptionReference ** >(
702                         uno_args[ 0 ] ) );
703                 if (typelib_TypeClass_INTERFACE !=
704                       demanded_td.get()->eTypeClass)
705                 {
706                     throw BridgeRuntimeError(
707                         OUSTR("queryInterface() call demands "
708                               "an INTERFACE type!") );
709                 }
710 
711                 uno_Interface * pInterface = 0;
712                 (*bridge->m_uno_env->getRegisteredInterface)(
713                     bridge->m_uno_env,
714                     (void **) &pInterface, that->m_oid.pData,
715                     (typelib_InterfaceTypeDescription *)demanded_td.get() );
716 
717                 if (0 == pInterface)
718                 {
719                     JNI_info const * jni_info = bridge->m_jni_info;
720                     JNI_guarded_context jni(
721                         jni_info,
722                         reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
723                             bridge->m_java_env->pContext ) );
724 
725                     JNI_interface_type_info const * info =
726                         static_cast< JNI_interface_type_info const * >(
727                             jni_info->get_type_info( jni, demanded_td.get() ) );
728 
729                     jvalue args[ 2 ];
730                     args[ 0 ].l = info->m_type;
731                     args[ 1 ].l = that->m_javaI;
732 
733                     JLocalAutoRef jo_ret(
734                         jni, jni->CallStaticObjectMethodA(
735                             jni_info->m_class_UnoRuntime,
736                             jni_info->m_method_UnoRuntime_queryInterface,
737                             args ) );
738 
739                     if (jni->ExceptionCheck())
740                     {
741                         JLocalAutoRef jo_exc( jni, jni->ExceptionOccurred() );
742                         jni->ExceptionClear();
743                         bridge->handle_java_exc( jni, jo_exc, *uno_exc );
744                     }
745                     else
746                     {
747                         if (jo_ret.is())
748                         {
749 #if OSL_DEBUG_LEVEL > 0
750                             JLocalAutoRef jo_oid(
751                                 jni, compute_oid( jni, jo_ret.get() ) );
752                             OUString oid( jstring_to_oustring(
753                                               jni, (jstring) jo_oid.get() ) );
754                             OSL_ENSURE(
755                                 oid.equals( that->m_oid ),
756                                 "### different oids!" );
757 #endif
758                             // refcount initially 1
759                             uno_Interface * pUnoI2 = new UNO_proxy(
760                                 jni, bridge, jo_ret.get(),
761                                 that->m_jo_oid, that->m_oid, info );
762 
763                             (*bridge->m_uno_env->registerProxyInterface)(
764                                 bridge->m_uno_env,
765                                 (void **) &pUnoI2,
766                                 UNO_proxy_free, that->m_oid.pData,
767                                 reinterpret_cast<
768                                   typelib_InterfaceTypeDescription * >(
769                                       info->m_td.get() ) );
770 
771                             uno_any_construct(
772                                 (uno_Any *)uno_ret, &pUnoI2,
773                                 demanded_td.get(), 0 );
774                             (*pUnoI2->release)( pUnoI2 );
775                         }
776                         else // object does not support demanded interface
777                         {
778                             uno_any_construct(
779                                 reinterpret_cast< uno_Any * >( uno_ret ),
780                                 0, 0, 0 );
781                         }
782                         // no exception occured
783                         *uno_exc = 0;
784                     }
785                 }
786                 else
787                 {
788                     uno_any_construct(
789                         reinterpret_cast< uno_Any * >( uno_ret ),
790                         &pInterface, demanded_td.get(), 0 );
791                     (*pInterface->release)( pInterface );
792                     *uno_exc = 0;
793                 }
794                 break;
795             }
796             case 1: // acquire this proxy
797                 that->acquire();
798                 *uno_exc = 0;
799                 break;
800             case 2: // release this proxy
801                 that->release();
802                 *uno_exc = 0;
803                 break;
804             default: // arbitrary method call
805                 bridge->call_java(
806                     that->m_javaI, iface_td, method_td->nIndex, 0,
807                     method_td->pReturnTypeRef,
808                     method_td->pParams, method_td->nParams,
809                     uno_ret, uno_args, uno_exc );
810                 break;
811             }
812             break;
813         }
814         default:
815         {
816             throw BridgeRuntimeError(
817                 OUSTR("illegal member type description!") );
818         }
819         }
820     }
821     catch (BridgeRuntimeError & err)
822     {
823         OUStringBuffer buf( 128 );
824         buf.appendAscii(
825             RTL_CONSTASCII_STRINGPARAM(
826                 "[jni_uno bridge error] UNO calling Java method ") );
827         if (typelib_TypeClass_INTERFACE_METHOD == member_td->eTypeClass ||
828             typelib_TypeClass_INTERFACE_ATTRIBUTE == member_td->eTypeClass)
829         {
830             buf.append( OUString::unacquired(
831                             &reinterpret_cast<
832                             typelib_InterfaceMemberTypeDescription const * >(
833                                 member_td )->pMemberName ) );
834         }
835         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") );
836         buf.append( err.m_message );
837         // binary identical struct
838         ::com::sun::star::uno::RuntimeException exc(
839             buf.makeStringAndClear(),
840             ::com::sun::star::uno::Reference<
841               ::com::sun::star::uno::XInterface >() );
842         ::com::sun::star::uno::Type const & exc_type = ::getCppuType( &exc );
843         uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0 );
844 #if OSL_DEBUG_LEVEL > 0
845         OString cstr_msg2(
846             OUStringToOString( exc.Message, RTL_TEXTENCODING_ASCII_US ) );
847         OSL_TRACE( "%s", cstr_msg2.getStr() );
848 #endif
849     }
850     catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
851     {
852         // binary identical struct
853         ::com::sun::star::uno::RuntimeException exc(
854             OUSTR("[jni_uno bridge error] attaching current thread "
855                   "to java failed!"),
856             ::com::sun::star::uno::Reference<
857               ::com::sun::star::uno::XInterface >() );
858         ::com::sun::star::uno::Type const & exc_type = ::getCppuType( &exc );
859         uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0 );
860 #if OSL_DEBUG_LEVEL > 0
861         OString cstr_msg2(
862             OUStringToOString( exc.Message, RTL_TEXTENCODING_ASCII_US ) );
863         OSL_ENSURE( 0, cstr_msg2.getStr() );
864 #endif
865     }
866 }
867 
868 }
869 }
870