bump product version to 4.1.6.2
[LibreOffice.git] / bridges / source / jni_uno / jni_java2uno.cxx
blobb6a200ea46f53a69eef46ebb4b6f020922c03a93
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <sal/alloca.h>
23 #include "jni_bridge.h"
25 #include <rtl/ustrbuf.hxx>
27 #include <algorithm>
30 using namespace ::rtl;
32 namespace jni_uno
35 //______________________________________________________________________________
36 jobject Bridge::map_to_java(
37 JNI_context const & jni,
38 uno_Interface * pUnoI, JNI_interface_type_info const * info ) const
40 // get oid
41 rtl_uString * pOid = 0;
42 (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
43 OSL_ASSERT( 0 != pOid );
44 OUString oid( pOid, SAL_NO_ACQUIRE );
46 // opt getRegisteredInterface()
47 JLocalAutoRef jo_oid( jni, ustring_to_jstring( jni, oid.pData ) );
48 jvalue args[ 2 ];
49 args[ 0 ].l = jo_oid.get();
50 args[ 1 ].l = info->m_type;
51 jobject jo_iface = jni->CallObjectMethodA(
52 m_jni_info->m_object_java_env,
53 m_jni_info->m_method_IEnvironment_getRegisteredInterface, args );
54 jni.ensure_no_exception();
56 if (0 == jo_iface) // no registered iface
58 // register uno interface
59 (*m_uno_env->registerInterface)(
60 m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
61 oid.pData, (typelib_InterfaceTypeDescription *)info->m_td.get() );
63 // create java and register java proxy
64 jvalue args2[ 7 ];
65 acquire();
66 args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this );
67 (*pUnoI->acquire)( pUnoI );
68 args2[ 1 ].l = m_jni_info->m_object_java_env;
69 args2[ 2 ].j = reinterpret_cast< sal_Int64 >( pUnoI );
70 typelib_typedescription_acquire( info->m_td.get() );
71 args2[ 3 ].j = reinterpret_cast< sal_Int64 >( info->m_td.get() );
72 args2[ 4 ].l = info->m_type;
73 args2[ 5 ].l = jo_oid.get();
74 args2[ 6 ].l = info->m_proxy_ctor;
75 jo_iface = jni->CallStaticObjectMethodA(
76 m_jni_info->m_class_JNI_proxy,
77 m_jni_info->m_method_JNI_proxy_create, args2 );
78 jni.ensure_no_exception();
81 OSL_ASSERT( 0 != jo_iface );
82 return jo_iface;
86 //______________________________________________________________________________
87 void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
89 if (typelib_TypeClass_EXCEPTION == uno_exc->pType->eTypeClass)
91 #if OSL_DEBUG_LEVEL > 0
92 // append java stack trace to Message member
93 reinterpret_cast< ::com::sun::star::uno::Exception * >(
94 uno_exc->pData )->Message += jni.get_stack_trace();
95 #endif
97 #if OSL_DEBUG_LEVEL > 1
99 OUStringBuffer buf( 128 );
100 buf.append( "exception occurred java->uno: [" );
101 buf.append( OUString::unacquired( &uno_exc->pType->pTypeName ) );
102 buf.append( "] " );
103 buf.append(
104 reinterpret_cast< ::com::sun::star::uno::Exception const * >(
105 uno_exc->pData )->Message );
106 OString cstr_msg(
107 OUStringToOString(
108 buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
109 OSL_TRACE( "%s", cstr_msg.getStr() );
111 #endif
112 // signal exception
113 jvalue java_exc;
116 map_to_java(
117 jni, &java_exc, uno_exc->pData, uno_exc->pType, 0,
118 true /* in */, false /* no out */ );
120 catch (...)
122 uno_any_destruct( uno_exc, 0 );
123 throw;
125 uno_any_destruct( uno_exc, 0 );
127 JLocalAutoRef jo_exc( jni, java_exc.l );
128 jint res = jni->Throw( (jthrowable) jo_exc.get() );
129 if (0 != res)
131 // call toString()
132 JLocalAutoRef jo_descr(
133 jni, jni->CallObjectMethodA(
134 jo_exc.get(), m_jni_info->m_method_Object_toString, 0 ) );
135 jni.ensure_no_exception();
136 OUStringBuffer buf( 128 );
137 buf.append( "throwing java exception failed: " );
138 buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) );
139 buf.append( jni.get_stack_trace() );
140 throw BridgeRuntimeError( buf.makeStringAndClear() );
143 else
145 OUString message(
146 "thrown exception is no uno exception: " +
147 OUString::unacquired( &uno_exc->pType->pTypeName ) +
148 jni.get_stack_trace() );
149 uno_any_destruct( uno_exc, 0 );
150 throw BridgeRuntimeError( message );
154 union largest
156 sal_Int64 n;
157 double d;
158 void * p;
159 uno_Any a;
162 //______________________________________________________________________________
163 jobject Bridge::call_uno(
164 JNI_context const & jni,
165 uno_Interface * pUnoI, typelib_TypeDescription * member_td,
166 typelib_TypeDescriptionReference * return_type,
167 sal_Int32 nParams, typelib_MethodParameter const * pParams,
168 jobjectArray jo_args /* may be 0 */ ) const
170 // return mem
171 sal_Int32 return_size;
172 switch (return_type->eTypeClass) {
173 case typelib_TypeClass_VOID:
174 return_size = 0;
175 break;
177 case typelib_TypeClass_STRUCT:
178 case typelib_TypeClass_EXCEPTION:
179 return_size = std::max(
180 TypeDescr(return_type).get()->nSize,
181 static_cast< sal_Int32 >(sizeof (largest)));
182 break;
184 default:
185 return_size = sizeof (largest);
186 break;
189 #ifdef BROKEN_ALLOCA
190 char * mem = (char *) malloc(
191 #else
192 char * mem = (char *) alloca(
193 #endif
194 (nParams * sizeof (void *)) +
195 return_size + (nParams * sizeof (largest)) );
196 void ** uno_args = (void **) mem;
197 void * uno_ret = return_size == 0 ? 0 : (mem + (nParams * sizeof (void *)));
198 largest * uno_args_mem = (largest *)
199 (mem + (nParams * sizeof (void *)) + return_size);
201 OSL_ASSERT( (0 == nParams) || (nParams == jni->GetArrayLength( jo_args )) );
202 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
204 typelib_MethodParameter const & param = pParams[ nPos ];
205 typelib_TypeDescriptionReference * type = param.pTypeRef;
207 uno_args[ nPos ] = &uno_args_mem[ nPos ];
208 if (typelib_TypeClass_STRUCT == type->eTypeClass ||
209 typelib_TypeClass_EXCEPTION == type->eTypeClass)
211 TypeDescr td( type );
212 if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
213 > sizeof (largest))
214 #ifdef BROKEN_ALLOCA
215 uno_args[ nPos ] = malloc( td.get()->nSize );
216 #else
217 uno_args[ nPos ] = alloca( td.get()->nSize );
218 #endif
221 if (param.bIn)
225 JLocalAutoRef jo_arg(
226 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
227 jni.ensure_no_exception();
228 jvalue java_arg;
229 java_arg.l = jo_arg.get();
230 map_to_uno(
231 jni, uno_args[ nPos ], java_arg, type, 0,
232 false /* no assign */, sal_False != param.bOut,
233 true /* special wrapped integral types */ );
235 catch (...)
237 // cleanup uno in args
238 for ( sal_Int32 n = 0; n < nPos; ++n )
240 typelib_MethodParameter const & p = pParams[ n ];
241 if (p.bIn)
243 uno_type_destructData(
244 uno_args[ n ], p.pTypeRef, 0 );
246 #ifdef BROKEN_ALLOCA
247 if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
248 free( uno_args[ nPos ] );
249 #endif
251 #ifdef BROKEN_ALLOCA
252 free( mem );
253 #endif
254 throw;
259 uno_Any uno_exc_holder;
260 uno_Any * uno_exc = &uno_exc_holder;
261 // call binary uno
262 (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
264 if (0 == uno_exc)
266 // convert out args; destruct uno args
267 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
269 typelib_MethodParameter const & param = pParams[ nPos ];
270 typelib_TypeDescriptionReference * type = param.pTypeRef;
271 if (param.bOut)
275 // get out holder array[ 1 ]
276 JLocalAutoRef jo_out_holder(
277 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
278 jni.ensure_no_exception();
279 jvalue java_arg;
280 java_arg.l = jo_out_holder.get();
281 map_to_java(
282 jni, &java_arg, uno_args[ nPos ], type, 0,
283 true /* in */, true /* out holder */ );
285 catch (...)
287 // cleanup further uno args
288 for ( sal_Int32 n = nPos; n < nParams; ++n )
290 uno_type_destructData(
291 uno_args[ n ], pParams[ n ].pTypeRef, 0 );
292 #ifdef BROKEN_ALLOCA
293 if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
294 free( uno_args[ nPos ] );
295 #endif
297 // cleanup uno return value
298 uno_type_destructData( uno_ret, return_type, 0 );
299 #ifdef BROKEN_ALLOCA
300 free( mem );
301 #endif
302 throw;
305 if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
306 typelib_TypeClass_ENUM != type->eTypeClass) // opt
308 uno_type_destructData( uno_args[ nPos ], type, 0 );
309 #ifdef BROKEN_ALLOCA
310 if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
311 free( uno_args[ nPos ] );
312 #endif
316 if (typelib_TypeClass_VOID != return_type->eTypeClass)
318 // convert uno return value
319 jvalue java_ret;
322 map_to_java(
323 jni, &java_ret, uno_ret, return_type, 0,
324 true /* in */, false /* no out */,
325 true /* special_wrapped_integral_types */ );
327 catch (...)
329 uno_type_destructData( uno_ret, return_type, 0 );
330 #ifdef BROKEN_ALLOCA
331 free( mem );
332 #endif
333 throw;
335 if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
336 typelib_TypeClass_ENUM != return_type->eTypeClass) // opt
338 uno_type_destructData( uno_ret, return_type, 0 );
340 #ifdef BROKEN_ALLOCA
341 free( mem );
342 #endif
343 return java_ret.l;
345 #ifdef BROKEN_ALLOCA
346 free( mem );
347 #endif
348 return 0; // void return
350 else // exception occurred
352 // destruct uno in args
353 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
355 typelib_MethodParameter const & param = pParams[ nPos ];
356 if (param.bIn)
357 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, 0 );
358 #ifdef BROKEN_ALLOCA
359 if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
360 free( uno_args[ nPos ] );
361 #endif
364 handle_uno_exc( jni, uno_exc );
365 #ifdef BROKEN_ALLOCA
366 free( mem );
367 #endif
368 return 0;
374 using namespace ::jni_uno;
376 extern "C"
379 //------------------------------------------------------------------------------
380 SAL_JNI_EXPORT jobject
381 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
382 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
383 jobjectArray jo_args /* may be 0 */ )
384 SAL_THROW_EXTERN_C()
386 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
387 JNI_info const * jni_info = bridge->m_jni_info;
388 JNI_context jni(
389 jni_info, jni_env,
390 static_cast< jobject >(
391 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
392 bridge->m_java_env->pContext )->getClassLoader() ) );
394 OUString method_name;
398 method_name = jstring_to_oustring( jni, jo_method );
399 #if OSL_DEBUG_LEVEL > 1
401 OUStringBuffer trace_buf( 64 );
402 trace_buf.append( "java->uno call: " );
403 trace_buf.append( method_name );
404 trace_buf.append( " on oid " );
405 JLocalAutoRef jo_oid(
406 jni, jni->GetObjectField(
407 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
408 trace_buf.append( jstring_to_oustring( jni, (jstring) jo_oid.get() ) );
409 OString cstr_msg(
410 OUStringToOString(
411 trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
412 OSL_TRACE( "%s", cstr_msg.getStr() );
414 #endif
416 // special IQueryInterface.queryInterface()
417 if ( method_name == "queryInterface" )
419 // oid
420 JLocalAutoRef jo_oid(
421 jni, jni->GetObjectField(
422 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
423 // type
424 JLocalAutoRef jo_type(
425 jni, jni->GetObjectArrayElement( jo_args, 0 ) );
426 jni.ensure_no_exception();
428 JLocalAutoRef jo_type_name(
429 jni, jni->GetObjectField(
430 jo_type.get(), jni_info->m_field_Type__typeName ) );
431 if (! jo_type_name.is())
433 throw BridgeRuntimeError(
434 "incomplete type object: no type name!" +
435 jni.get_stack_trace() );
437 OUString type_name(
438 jstring_to_oustring( jni, (jstring) jo_type_name.get() ) );
439 JNI_type_info const * info =
440 jni_info->get_type_info( jni, type_name );
441 if (typelib_TypeClass_INTERFACE != info->m_td.get()->eTypeClass)
443 throw BridgeRuntimeError(
444 "queryInterface() call demands an INTERFACE type!" );
446 JNI_interface_type_info const * iface_info =
447 static_cast< JNI_interface_type_info const * >( info );
449 // getRegisteredInterface() already tested in JNI_proxy:
450 // perform queryInterface call on binary uno interface
451 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
452 jni->GetLongField(
453 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
455 uno_Any uno_ret;
456 void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
457 uno_Any uno_exc_holder;
458 uno_Any * uno_exc = &uno_exc_holder;
459 // call binary uno
460 (*pUnoI->pDispatcher)(
461 pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
462 &uno_ret, uno_args, &uno_exc );
463 if (0 == uno_exc)
465 jobject jo_ret = 0;
466 if (typelib_TypeClass_INTERFACE == uno_ret.pType->eTypeClass)
468 uno_Interface * pUnoRet =
469 (uno_Interface *) uno_ret.pReserved;
470 if (0 != pUnoRet)
474 jo_ret =
475 bridge->map_to_java( jni, pUnoRet, iface_info );
477 catch (...)
479 uno_any_destruct( &uno_ret, 0 );
480 throw;
484 uno_any_destruct( &uno_ret, 0 );
485 return jo_ret;
487 else
489 bridge->handle_uno_exc( jni, uno_exc );
490 return 0;
494 typelib_InterfaceTypeDescription * td =
495 reinterpret_cast< typelib_InterfaceTypeDescription * >(
496 jni->GetLongField(
497 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
498 uno_Interface * pUnoI =
499 reinterpret_cast< uno_Interface * >(
500 jni->GetLongField(
501 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
503 typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
504 for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
506 // try to avoid getting typedescription as long as possible,
507 // because of a Mutex.acquire() in
508 // typelib_typedescriptionreference_getDescription()
509 typelib_TypeDescriptionReference * member_type =
510 ppAllMembers[ nPos ];
512 // check method_name against fully qualified type_name
513 // of member_type; type_name is of the form
514 // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
515 OUString const & type_name =
516 OUString::unacquired( &member_type->pTypeName );
517 sal_Int32 offset = type_name.indexOf( ':' ) + 2;
518 OSL_ASSERT(
519 offset >= 2 && offset < type_name.getLength()
520 && type_name[offset - 1] == ':' );
521 sal_Int32 remainder = type_name.getLength() - offset;
522 if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
524 if ((method_name.getLength() == remainder
525 || (method_name.getLength() < remainder
526 && type_name[offset + method_name.getLength()] == ':'))
527 && type_name.match(method_name, offset))
529 TypeDescr member_td( member_type );
530 typelib_InterfaceMethodTypeDescription * method_td =
531 reinterpret_cast<
532 typelib_InterfaceMethodTypeDescription * >(
533 member_td.get() );
534 return bridge->call_uno(
535 jni, pUnoI, member_td.get(),
536 method_td->pReturnTypeRef,
537 method_td->nParams, method_td->pParams,
538 jo_args );
541 else // attribute
543 OSL_ASSERT(
544 typelib_TypeClass_INTERFACE_ATTRIBUTE ==
545 member_type->eTypeClass );
547 if (method_name.getLength() >= 3
548 && (method_name.getLength() - 3 == remainder
549 || (method_name.getLength() - 3 < remainder
550 && type_name[
551 offset + (method_name.getLength() - 3)] == ':'))
552 && method_name[1] == 'e' && method_name[2] == 't'
553 && rtl_ustr_compare_WithLength(
554 type_name.getStr() + offset,
555 method_name.getLength() - 3,
556 method_name.getStr() + 3,
557 method_name.getLength() - 3) == 0)
559 if ('g' == method_name[ 0 ])
561 TypeDescr member_td( member_type );
562 typelib_InterfaceAttributeTypeDescription * attr_td =
563 reinterpret_cast<
564 typelib_InterfaceAttributeTypeDescription * >(
565 member_td.get() );
566 return bridge->call_uno(
567 jni, pUnoI, member_td.get(),
568 attr_td->pAttributeTypeRef,
569 0, 0,
570 jo_args );
572 else if ('s' == method_name[ 0 ])
574 TypeDescr member_td( member_type );
575 typelib_InterfaceAttributeTypeDescription * attr_td =
576 reinterpret_cast<
577 typelib_InterfaceAttributeTypeDescription * >(
578 member_td.get() );
579 if (! attr_td->bReadOnly)
581 typelib_MethodParameter param;
582 param.pTypeRef = attr_td->pAttributeTypeRef;
583 param.bIn = sal_True;
584 param.bOut = sal_False;
585 return bridge->call_uno(
586 jni, pUnoI, member_td.get(),
587 jni_info->m_void_type.getTypeLibType(),
588 1, &param,
589 jo_args );
595 // the thing that should not be... no method info found!
596 OUStringBuffer buf( 64 );
597 buf.append( "calling undeclared function on interface " );
598 buf.append( OUString::unacquired(
599 &((typelib_TypeDescription *)td)->pTypeName ) );
600 buf.append( ": " );
601 buf.append( method_name );
602 buf.append( jni.get_stack_trace() );
603 throw BridgeRuntimeError( buf.makeStringAndClear() );
605 catch (const BridgeRuntimeError & err)
607 OUStringBuffer buf( 128 );
608 buf.append( "[jni_uno bridge error] " "Java calling UNO method " );
609 buf.append( method_name );
610 buf.append( ": " );
611 buf.append( err.m_message );
612 // notify RuntimeException
613 OString cstr_msg(
614 OUStringToOString(
615 buf.makeStringAndClear(), RTL_TEXTENCODING_JAVA_UTF8 ) );
616 OSL_FAIL( cstr_msg.getStr() );
617 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
618 != 0)
620 OSL_ASSERT( false );
622 return 0;
624 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
626 OString cstr_msg(
627 OString( "[jni_uno bridge error] "
628 "attaching current thread to java failed!" ) +
629 OUStringToOString(
630 jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8 ) );
631 OSL_FAIL( cstr_msg.getStr() );
632 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
633 != 0)
635 OSL_ASSERT( false );
637 return 0;
641 //------------------------------------------------------------------------------
642 SAL_JNI_EXPORT void
643 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
644 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
645 SAL_THROW_EXTERN_C()
647 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
648 JNI_info const * jni_info = bridge->m_jni_info;
649 JNI_context jni(
650 jni_info, jni_env,
651 static_cast< jobject >(
652 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
653 bridge->m_java_env->pContext )->getClassLoader() ) );
655 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
656 jni->GetLongField(
657 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
658 typelib_TypeDescription * td =
659 reinterpret_cast< typelib_TypeDescription * >(
660 jni->GetLongField(
661 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
663 #if OSL_DEBUG_LEVEL > 1
665 JLocalAutoRef jo_oid(
666 jni, jni->GetObjectField(
667 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
668 OUString oid( jstring_to_oustring( jni, (jstring) jo_oid.get() ) );
669 OString cstr_msg(
670 OUStringToOString(
671 "freeing java uno proxy: " + oid,
672 RTL_TEXTENCODING_ASCII_US ) );
673 OSL_TRACE( "%s", cstr_msg.getStr() );
675 #endif
676 // revoke from uno env; has already been revoked from java env
677 (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
678 // release receiver
679 (*pUnoI->release)( pUnoI );
680 // release typedescription handle
681 typelib_typedescription_release( td );
682 // release bridge handle
683 bridge->release();
688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */