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 "jni_bridge.h"
30 //#include "jni_finalizer.h"
31 
32 #include <rtl/ustrbuf.hxx>
33 
34 #include <algorithm>
35 
36 
37 using namespace ::rtl;
38 
39 namespace jni_uno
40 {
41 
42 //______________________________________________________________________________
43 jobject Bridge::map_to_java(
44     JNI_context const & jni,
45     uno_Interface * pUnoI, JNI_interface_type_info const * info ) const
46 {
47     // get oid
48     rtl_uString * pOid = 0;
49     (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
50     OSL_ASSERT( 0 != pOid );
51     OUString oid( pOid, SAL_NO_ACQUIRE );
52 
53     // opt getRegisteredInterface()
54     JLocalAutoRef jo_oid( jni, ustring_to_jstring( jni, oid.pData ) );
55     jvalue args[ 2 ];
56     args[ 0 ].l = jo_oid.get();
57     args[ 1 ].l = info->m_type;
58     jobject jo_iface = jni->CallObjectMethodA(
59         m_jni_info->m_object_java_env,
60         m_jni_info->m_method_IEnvironment_getRegisteredInterface, args );
61     jni.ensure_no_exception();
62 
63     if (0 == jo_iface) // no registered iface
64     {
65         // register uno interface
66         (*m_uno_env->registerInterface)(
67             m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
68             oid.pData, (typelib_InterfaceTypeDescription *)info->m_td.get() );
69 
70         // create java and register java proxy
71         jvalue args2[ 7 ];
72         acquire();
73         args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this );
74         (*pUnoI->acquire)( pUnoI );
75         args2[ 1 ].l = m_jni_info->m_object_java_env;
76         args2[ 2 ].j = reinterpret_cast< sal_Int64 >( pUnoI );
77         typelib_typedescription_acquire( info->m_td.get() );
78         args2[ 3 ].j = reinterpret_cast< sal_Int64 >( info->m_td.get() );
79         args2[ 4 ].l = info->m_type;
80         args2[ 5 ].l = jo_oid.get();
81         args2[ 6 ].l = info->m_proxy_ctor;
82         jo_iface = jni->CallStaticObjectMethodA(
83             m_jni_info->m_class_JNI_proxy,
84             m_jni_info->m_method_JNI_proxy_create, args2 );
85         jni.ensure_no_exception();
86     }
87 
88     OSL_ASSERT( 0 != jo_iface );
89     return jo_iface;
90 }
91 
92 
93 //______________________________________________________________________________
94 void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
95 {
96     if (typelib_TypeClass_EXCEPTION == uno_exc->pType->eTypeClass)
97     {
98 #if OSL_DEBUG_LEVEL > 0
99         // append java stack trace to Message member
100         reinterpret_cast< ::com::sun::star::uno::Exception * >(
101             uno_exc->pData )->Message += jni.get_stack_trace();
102 #endif
103 
104 #if OSL_DEBUG_LEVEL > 1
105         {
106         OUStringBuffer buf( 128 );
107         buf.appendAscii(
108             RTL_CONSTASCII_STRINGPARAM("exception occurred java->uno: [") );
109         buf.append( OUString::unacquired( &uno_exc->pType->pTypeName ) );
110         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] ") );
111         buf.append(
112             reinterpret_cast< ::com::sun::star::uno::Exception const * >(
113                 uno_exc->pData )->Message );
114         OString cstr_msg(
115             OUStringToOString(
116                 buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
117         OSL_TRACE( cstr_msg.getStr() );
118         }
119 #endif
120         // signal exception
121         jvalue java_exc;
122         try
123         {
124             map_to_java(
125                 jni, &java_exc, uno_exc->pData, uno_exc->pType, 0,
126                 true /* in */, false /* no out */ );
127         }
128         catch (...)
129         {
130             uno_any_destruct( uno_exc, 0 );
131             throw;
132         }
133         uno_any_destruct( uno_exc, 0 );
134 
135         JLocalAutoRef jo_exc( jni, java_exc.l );
136         jint res = jni->Throw( (jthrowable) jo_exc.get() );
137         if (0 != res)
138         {
139             // call toString()
140             JLocalAutoRef jo_descr(
141                 jni, jni->CallObjectMethodA(
142                     jo_exc.get(), m_jni_info->m_method_Object_toString, 0 ) );
143             jni.ensure_no_exception();
144             OUStringBuffer buf( 128 );
145             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
146                                  "throwing java exception failed: ") );
147             buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) );
148             buf.append( jni.get_stack_trace() );
149             throw BridgeRuntimeError( buf.makeStringAndClear() );
150         }
151     }
152     else
153     {
154         OUString message(
155             OUSTR("thrown exception is no uno exception: ") +
156             OUString::unacquired( &uno_exc->pType->pTypeName ) +
157             jni.get_stack_trace() );
158         uno_any_destruct( uno_exc, 0 );
159         throw BridgeRuntimeError( message );
160     }
161 }
162 
163 union largest
164 {
165     sal_Int64 n;
166     double d;
167     void * p;
168     uno_Any a;
169 };
170 
171 //______________________________________________________________________________
172 jobject Bridge::call_uno(
173     JNI_context const & jni,
174     uno_Interface * pUnoI, typelib_TypeDescription * member_td,
175     typelib_TypeDescriptionReference * return_type,
176     sal_Int32 nParams, typelib_MethodParameter const * pParams,
177     jobjectArray jo_args /* may be 0 */ ) const
178 {
179     // return mem
180     sal_Int32 return_size;
181     switch (return_type->eTypeClass) {
182     case typelib_TypeClass_VOID:
183         return_size = 0;
184         break;
185 
186     case typelib_TypeClass_STRUCT:
187     case typelib_TypeClass_EXCEPTION:
188         return_size = std::max(
189             TypeDescr(return_type).get()->nSize,
190             static_cast< sal_Int32 >(sizeof (largest)));
191         break;
192 
193     default:
194         return_size = sizeof (largest);
195         break;
196     }
197 
198 #ifdef BROKEN_ALLOCA
199     char * mem = (char *) malloc(
200 #else
201     char * mem = (char *) alloca(
202 #endif
203         (nParams * sizeof (void *)) +
204         return_size + (nParams * sizeof (largest)) );
205     void ** uno_args = (void **) mem;
206     void * uno_ret = return_size == 0 ? 0 : (mem + (nParams * sizeof (void *)));
207     largest * uno_args_mem = (largest *)
208         (mem + (nParams * sizeof (void *)) + return_size);
209 
210     OSL_ASSERT( (0 == nParams) || (nParams == jni->GetArrayLength( jo_args )) );
211     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
212     {
213         typelib_MethodParameter const & param = pParams[ nPos ];
214         typelib_TypeDescriptionReference * type = param.pTypeRef;
215 
216         uno_args[ nPos ] = &uno_args_mem[ nPos ];
217         if (typelib_TypeClass_STRUCT == type->eTypeClass ||
218             typelib_TypeClass_EXCEPTION == type->eTypeClass)
219         {
220             TypeDescr td( type );
221             if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
222                 > sizeof (largest))
223 #ifdef BROKEN_ALLOCA
224                 uno_args[ nPos ] = malloc( td.get()->nSize );
225 #else
226                 uno_args[ nPos ] = alloca( td.get()->nSize );
227 #endif
228         }
229 
230         if (param.bIn)
231         {
232             try
233             {
234                 JLocalAutoRef jo_arg(
235                     jni, jni->GetObjectArrayElement( jo_args, nPos ) );
236                 jni.ensure_no_exception();
237                 jvalue java_arg;
238                 java_arg.l = jo_arg.get();
239                 map_to_uno(
240                     jni, uno_args[ nPos ], java_arg, type, 0,
241                     false /* no assign */, sal_False != param.bOut,
242                     true /* special wrapped integral types */ );
243             }
244             catch (...)
245             {
246                 // cleanup uno in args
247                 for ( sal_Int32 n = 0; n < nPos; ++n )
248                 {
249                     typelib_MethodParameter const & p = pParams[ n ];
250                     if (p.bIn)
251                     {
252                         uno_type_destructData(
253                             uno_args[ n ], p.pTypeRef, 0 );
254                     }
255 #ifdef BROKEN_ALLOCA
256 		    if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
257 			free( uno_args[ nPos ] );
258 #endif
259                 }
260 #ifdef BROKEN_ALLOCA
261 		free( mem );
262 #endif
263                 throw;
264             }
265         }
266     }
267 
268     uno_Any uno_exc_holder;
269     uno_Any * uno_exc = &uno_exc_holder;
270     // call binary uno
271     (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
272 
273     if (0 == uno_exc)
274     {
275         // convert out args; destruct uno args
276         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
277         {
278             typelib_MethodParameter const & param = pParams[ nPos ];
279             typelib_TypeDescriptionReference * type = param.pTypeRef;
280             if (param.bOut)
281             {
282                 try
283                 {
284                     // get out holder array[ 1 ]
285                     JLocalAutoRef jo_out_holder(
286                         jni, jni->GetObjectArrayElement( jo_args, nPos ) );
287                     jni.ensure_no_exception();
288                     jvalue java_arg;
289                     java_arg.l = jo_out_holder.get();
290                     map_to_java(
291                         jni, &java_arg, uno_args[ nPos ], type, 0,
292                         true /* in */, true /* out holder */ );
293                 }
294                 catch (...)
295                 {
296                     // cleanup further uno args
297                     for ( sal_Int32 n = nPos; n < nParams; ++n )
298                     {
299                         uno_type_destructData(
300                             uno_args[ n ], pParams[ n ].pTypeRef, 0 );
301 #ifdef BROKEN_ALLOCA
302 			if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
303 			    free( uno_args[ nPos ] );
304 #endif
305                     }
306                     // cleanup uno return value
307                     uno_type_destructData( uno_ret, return_type, 0 );
308 #ifdef BROKEN_ALLOCA
309 		    free( mem );
310 #endif
311                     throw;
312                 }
313             }
314             if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
315                 typelib_TypeClass_ENUM != type->eTypeClass) // opt
316             {
317                 uno_type_destructData( uno_args[ nPos ], type, 0 );
318 #ifdef BROKEN_ALLOCA
319 		if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
320 		    free( uno_args[ nPos ] );
321 #endif
322             }
323         }
324 
325         if (typelib_TypeClass_VOID != return_type->eTypeClass)
326         {
327             // convert uno return value
328             jvalue java_ret;
329             try
330             {
331                 map_to_java(
332                     jni, &java_ret, uno_ret, return_type, 0,
333                     true /* in */, false /* no out */,
334                     true /* special_wrapped_integral_types */ );
335             }
336             catch (...)
337             {
338                 uno_type_destructData( uno_ret, return_type, 0 );
339 #ifdef BROKEN_ALLOCA
340 		free( mem );
341 #endif
342                 throw;
343             }
344             if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
345                 typelib_TypeClass_ENUM != return_type->eTypeClass) // opt
346             {
347                 uno_type_destructData( uno_ret, return_type, 0 );
348             }
349 #ifdef BROKEN_ALLOCA
350 	    free( mem );
351 #endif
352             return java_ret.l;
353         }
354 #ifdef BROKEN_ALLOCA
355 	free( mem );
356 #endif
357         return 0; // void return
358     }
359     else // exception occurred
360     {
361         // destruct uno in args
362         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
363         {
364             typelib_MethodParameter const & param = pParams[ nPos ];
365             if (param.bIn)
366                 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, 0 );
367 #ifdef BROKEN_ALLOCA
368 		if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
369 		    free( uno_args[ nPos ] );
370 #endif
371         }
372 
373         handle_uno_exc( jni, uno_exc );
374 #ifdef BROKEN_ALLOCA
375 	free( mem );
376 #endif
377         return 0;
378     }
379 }
380 
381 }
382 
383 using namespace ::jni_uno;
384 
385 extern "C"
386 {
387 
388 //------------------------------------------------------------------------------
389 JNIEXPORT jobject
390 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
391     JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring,
392     jstring jo_method, jobjectArray jo_args /* may be 0 */ )
393     SAL_THROW_EXTERN_C()
394 {
395     Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
396     JNI_info const * jni_info = bridge->m_jni_info;
397     JNI_context jni(
398         jni_info, jni_env,
399         static_cast< jobject >(
400             reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
401                 bridge->m_java_env->pContext )->getClassLoader() ) );
402 
403     OUString method_name;
404 
405     try
406     {
407         method_name = jstring_to_oustring( jni, jo_method );
408 #if OSL_DEBUG_LEVEL > 1
409         {
410         OUStringBuffer trace_buf( 64 );
411         trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("java->uno call: ") );
412         trace_buf.append( method_name );
413         trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" on oid ") );
414         JLocalAutoRef jo_oid(
415             jni, jni->GetObjectField(
416                 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
417         trace_buf.append( jstring_to_oustring( jni, (jstring) jo_oid.get() ) );
418         OString cstr_msg(
419             OUStringToOString(
420                 trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
421         OSL_TRACE( cstr_msg.getStr() );
422         }
423 #endif
424 
425         // special IQueryInterface.queryInterface()
426         if (method_name.equalsAsciiL(
427                 RTL_CONSTASCII_STRINGPARAM("queryInterface") ))
428         {
429             // oid
430             JLocalAutoRef jo_oid(
431                 jni, jni->GetObjectField(
432                     jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
433             // type
434             JLocalAutoRef jo_type(
435                 jni, jni->GetObjectArrayElement( jo_args, 0 ) );
436             jni.ensure_no_exception();
437 
438             JLocalAutoRef jo_type_name(
439                 jni, jni->GetObjectField(
440                     jo_type.get(), jni_info->m_field_Type__typeName ) );
441             if (! jo_type_name.is())
442             {
443                 throw BridgeRuntimeError(
444                     OUSTR("incomplete type object: no type name!") +
445                     jni.get_stack_trace() );
446             }
447             OUString type_name(
448                 jstring_to_oustring( jni, (jstring) jo_type_name.get() ) );
449             JNI_type_info const * info =
450                 jni_info->get_type_info( jni, type_name );
451             if (typelib_TypeClass_INTERFACE != info->m_td.get()->eTypeClass)
452             {
453                 throw BridgeRuntimeError(
454                     OUSTR("queryInterface() call demands an INTERFACE type!") );
455             }
456             JNI_interface_type_info const * iface_info =
457                 static_cast< JNI_interface_type_info const * >( info );
458 
459             // getRegisteredInterface() already tested in JNI_proxy:
460             // perform queryInterface call on binary uno interface
461             uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
462                 jni->GetLongField(
463                     jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
464 
465             uno_Any uno_ret;
466             void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
467             uno_Any uno_exc_holder;
468             uno_Any * uno_exc = &uno_exc_holder;
469             // call binary uno
470             (*pUnoI->pDispatcher)(
471                 pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
472                 &uno_ret, uno_args, &uno_exc );
473             if (0 == uno_exc)
474             {
475                 jobject jo_ret = 0;
476                 if (typelib_TypeClass_INTERFACE == uno_ret.pType->eTypeClass)
477                 {
478                     uno_Interface * pUnoRet =
479                         (uno_Interface *) uno_ret.pReserved;
480                     if (0 != pUnoRet)
481                     {
482                         try
483                         {
484                             jo_ret =
485                                 bridge->map_to_java( jni, pUnoRet, iface_info );
486                         }
487                         catch (...)
488                         {
489                             uno_any_destruct( &uno_ret, 0 );
490                             throw;
491                         }
492                     }
493                 }
494                 uno_any_destruct( &uno_ret, 0 );
495                 return jo_ret;
496             }
497             else
498             {
499                 bridge->handle_uno_exc( jni, uno_exc );
500                 return 0;
501             }
502         }
503 
504         typelib_InterfaceTypeDescription * td =
505             reinterpret_cast< typelib_InterfaceTypeDescription * >(
506                 jni->GetLongField(
507                     jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
508         uno_Interface * pUnoI =
509             reinterpret_cast< uno_Interface * >(
510                 jni->GetLongField(
511                     jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
512 
513         typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
514         for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
515         {
516             // try to avoid getting typedescription as long as possible,
517             // because of a Mutex.acquire() in
518             // typelib_typedescriptionreference_getDescription()
519             typelib_TypeDescriptionReference * member_type =
520                 ppAllMembers[ nPos ];
521 
522             // check method_name against fully qualified type_name
523             // of member_type; type_name is of the form
524             //  <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
525             OUString const & type_name =
526                 OUString::unacquired( &member_type->pTypeName );
527             sal_Int32 offset = type_name.indexOf( ':' ) + 2;
528             OSL_ASSERT(
529                 offset >= 2 && offset < type_name.getLength()
530                 && type_name[offset - 1] == ':' );
531             sal_Int32 remainder = type_name.getLength() - offset;
532             if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
533             {
534                 if ((method_name.getLength() == remainder
535                      || (method_name.getLength() < remainder
536                          && type_name[offset + method_name.getLength()] == ':'))
537                     && type_name.match(method_name, offset))
538                 {
539                     TypeDescr member_td( member_type );
540                     typelib_InterfaceMethodTypeDescription * method_td =
541                         reinterpret_cast<
542                           typelib_InterfaceMethodTypeDescription * >(
543                               member_td.get() );
544                     return bridge->call_uno(
545                         jni, pUnoI, member_td.get(),
546                         method_td->pReturnTypeRef,
547                         method_td->nParams, method_td->pParams,
548                         jo_args );
549                 }
550             }
551             else // attribute
552             {
553                 OSL_ASSERT(
554                     typelib_TypeClass_INTERFACE_ATTRIBUTE ==
555                       member_type->eTypeClass );
556 
557                 if (method_name.getLength() >= 3
558                     && (method_name.getLength() - 3 == remainder
559                         || (method_name.getLength() - 3 < remainder
560                             && type_name[
561                                 offset + (method_name.getLength() - 3)] == ':'))
562                     && method_name[1] == 'e' && method_name[2] == 't'
563                     && rtl_ustr_compare_WithLength(
564                         type_name.getStr() + offset,
565                         method_name.getLength() - 3,
566                         method_name.getStr() + 3,
567                         method_name.getLength() - 3) == 0)
568                 {
569                     if ('g' == method_name[ 0 ])
570                     {
571                         TypeDescr member_td( member_type );
572                         typelib_InterfaceAttributeTypeDescription * attr_td =
573                             reinterpret_cast<
574                               typelib_InterfaceAttributeTypeDescription * >(
575                                   member_td.get() );
576                         return bridge->call_uno(
577                             jni, pUnoI, member_td.get(),
578                             attr_td->pAttributeTypeRef,
579                             0, 0,
580                             jo_args );
581                     }
582                     else if ('s' == method_name[ 0 ])
583                     {
584                         TypeDescr member_td( member_type );
585                         typelib_InterfaceAttributeTypeDescription * attr_td =
586                             reinterpret_cast<
587                               typelib_InterfaceAttributeTypeDescription * >(
588                                   member_td.get() );
589                         if (! attr_td->bReadOnly)
590                         {
591                             typelib_MethodParameter param;
592                             param.pTypeRef = attr_td->pAttributeTypeRef;
593                             param.bIn = sal_True;
594                             param.bOut = sal_False;
595                             return bridge->call_uno(
596                                 jni, pUnoI, member_td.get(),
597                                 jni_info->m_void_type.getTypeLibType(),
598                                 1, &param,
599                                 jo_args );
600                         }
601                     }
602                 }
603             }
604         }
605         // the thing that should not be... no method info found!
606         OUStringBuffer buf( 64 );
607         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
608             "calling undeclared function on interface ") );
609         buf.append( OUString::unacquired(
610                         &((typelib_TypeDescription *)td)->pTypeName ) );
611         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") );
612         buf.append( method_name );
613         buf.append( jni.get_stack_trace() );
614         throw BridgeRuntimeError( buf.makeStringAndClear() );
615     }
616     catch (BridgeRuntimeError & err)
617     {
618         OUStringBuffer buf( 128 );
619         buf.appendAscii(
620             RTL_CONSTASCII_STRINGPARAM("[jni_uno bridge error] "
621                                        "Java calling UNO method ") );
622         buf.append( method_name );
623         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") );
624         buf.append( err.m_message );
625         // notify RuntimeException
626         OString cstr_msg(
627             OUStringToOString(
628                 buf.makeStringAndClear(), RTL_TEXTENCODING_JAVA_UTF8 ) );
629         OSL_ENSURE( 0, cstr_msg.getStr() );
630         if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
631             != 0)
632         {
633             OSL_ASSERT( false );
634         }
635         return 0;
636     }
637     catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
638     {
639         OString cstr_msg(
640             OString( RTL_CONSTASCII_STRINGPARAM(
641                 "[jni_uno bridge error] "
642                 "attaching current thread to java failed!") ) +
643             OUStringToOString(
644                 jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8 ) );
645         OSL_ENSURE( 0, cstr_msg.getStr() );
646         if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
647             != 0)
648         {
649             OSL_ASSERT( false );
650         }
651         return 0;
652     }
653 }
654 
655 //------------------------------------------------------------------------------
656 JNIEXPORT void
657 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
658     JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
659     SAL_THROW_EXTERN_C()
660 {
661     Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
662     JNI_info const * jni_info = bridge->m_jni_info;
663     JNI_context jni(
664         jni_info, jni_env,
665         static_cast< jobject >(
666             reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
667                 bridge->m_java_env->pContext )->getClassLoader() ) );
668 
669     uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
670         jni->GetLongField(
671             jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
672     typelib_TypeDescription * td =
673         reinterpret_cast< typelib_TypeDescription * >(
674             jni->GetLongField(
675                 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
676 
677 #if OSL_DEBUG_LEVEL > 1
678     {
679     JLocalAutoRef jo_oid(
680         jni, jni->GetObjectField(
681             jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
682     OUString oid( jstring_to_oustring( jni, (jstring) jo_oid.get() ) );
683     OString cstr_msg(
684         OUStringToOString(
685             OUSTR("freeing java uno proxy: ") + oid,
686             RTL_TEXTENCODING_ASCII_US ) );
687     OSL_TRACE( cstr_msg.getStr() );
688     }
689 #endif
690     // revoke from uno env; has already been revoked from java env
691     (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
692     // release receiver
693 	(*pUnoI->release)( pUnoI );
694     // release typedescription handle
695     typelib_typedescription_release( td );
696     // release bridge handle
697     bridge->release();
698 }
699 
700 }
701