bump product version to 5.0.4.1
[LibreOffice.git] / bridges / source / jni_uno / jni_java2uno.cxx
blob47064670c37610ed9b42d9e403a0c76eb49bd663
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 .
20 #include <sal/config.h>
22 #include <algorithm>
23 #include <cassert>
25 #include <sal/alloca.h>
27 #include "jni_bridge.h"
28 #include "jniunoenvironmentdata.hxx"
30 namespace jni_uno
34 jobject Bridge::map_to_java(
35 JNI_context const & jni,
36 uno_Interface * pUnoI, JNI_interface_type_info const * info ) const
38 // get oid
39 rtl_uString * pOid = 0;
40 (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
41 assert( 0 != pOid );
42 OUString oid( pOid, SAL_NO_ACQUIRE );
44 // opt getRegisteredInterface()
45 JLocalAutoRef jo_oid( jni, ustring_to_jstring( jni, oid.pData ) );
46 jvalue args[ 2 ];
47 args[ 0 ].l = jo_oid.get();
48 args[ 1 ].l = info->m_type;
49 jobject jo_iface = jni->CallObjectMethodA(
50 getJniInfo()->m_object_java_env,
51 getJniInfo()->m_method_IEnvironment_getRegisteredInterface, args );
52 jni.ensure_no_exception();
54 if (0 == jo_iface) // no registered iface
56 // register uno interface
57 (*m_uno_env->registerInterface)(
58 m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
59 oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
61 // create java and register java proxy
62 jvalue args2[ 8 ];
63 acquire();
64 args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this );
65 (*pUnoI->acquire)( pUnoI );
66 args2[ 1 ].l = getJniInfo()->m_object_java_env;
67 args2[ 2 ].j = reinterpret_cast< sal_Int64 >( pUnoI );
68 typelib_typedescription_acquire( info->m_td.get() );
69 args2[ 3 ].j = reinterpret_cast< sal_Int64 >( info->m_td.get() );
70 args2[ 4 ].l = info->m_type;
71 args2[ 5 ].l = jo_oid.get();
72 args2[ 6 ].l = info->m_proxy_ctor;
73 auto * envData = static_cast<jni_uno::JniUnoEnvironmentData *>(
74 m_java_env->pContext);
76 osl::MutexGuard g(envData->mutex);
77 args2[ 7 ].l = envData->asynchronousFinalizer;
79 jo_iface = jni->CallStaticObjectMethodA(
80 getJniInfo()->m_class_JNI_proxy,
81 getJniInfo()->m_method_JNI_proxy_create, args2 );
82 jni.ensure_no_exception();
85 assert( 0 != jo_iface );
86 return jo_iface;
91 void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
93 if (typelib_TypeClass_EXCEPTION == uno_exc->pType->eTypeClass)
95 #if OSL_DEBUG_LEVEL > 0
96 // append java stack trace to Message member
97 static_cast< ::com::sun::star::uno::Exception * >(
98 uno_exc->pData )->Message += jni.get_stack_trace();
99 #endif
100 SAL_INFO(
101 "bridges",
102 "exception occurred java->uno: ["
103 << OUString::unacquired(&uno_exc->pType->pTypeName) << "] "
104 << static_cast<css::uno::Exception const *>(
105 uno_exc->pData)->Message);
106 // signal exception
107 jvalue java_exc;
110 map_to_java(
111 jni, &java_exc, uno_exc->pData, uno_exc->pType, 0,
112 true /* in */, false /* no out */ );
114 catch (...)
116 uno_any_destruct( uno_exc, 0 );
117 throw;
119 uno_any_destruct( uno_exc, 0 );
121 JLocalAutoRef jo_exc( jni, java_exc.l );
122 jint res = jni->Throw( static_cast<jthrowable>(jo_exc.get()) );
123 if (0 != res)
125 // call toString()
126 JLocalAutoRef jo_descr(
127 jni, jni->CallObjectMethodA(
128 jo_exc.get(), getJniInfo()->m_method_Object_toString, 0 ) );
129 jni.ensure_no_exception();
130 throw BridgeRuntimeError(
131 "throwing java exception failed: "
132 + jstring_to_oustring( jni, static_cast<jstring>(jo_descr.get()) )
133 + jni.get_stack_trace() );
136 else
138 OUString message(
139 "thrown exception is no uno exception: " +
140 OUString::unacquired( &uno_exc->pType->pTypeName ) +
141 jni.get_stack_trace() );
142 uno_any_destruct( uno_exc, 0 );
143 throw BridgeRuntimeError( message );
147 union largest
149 sal_Int64 n;
150 double d;
151 void * p;
152 uno_Any a;
156 jobject Bridge::call_uno(
157 JNI_context const & jni,
158 uno_Interface * pUnoI, typelib_TypeDescription * member_td,
159 typelib_TypeDescriptionReference * return_type,
160 sal_Int32 nParams, typelib_MethodParameter const * pParams,
161 jobjectArray jo_args /* may be 0 */ ) const
163 // return mem
164 sal_Int32 return_size;
165 switch (return_type->eTypeClass) {
166 case typelib_TypeClass_VOID:
167 return_size = 0;
168 break;
170 case typelib_TypeClass_STRUCT:
171 case typelib_TypeClass_EXCEPTION:
172 return_size = std::max(
173 TypeDescr(return_type).get()->nSize,
174 static_cast< sal_Int32 >(sizeof (largest)));
175 break;
177 default:
178 return_size = sizeof (largest);
179 break;
182 #ifdef BROKEN_ALLOCA
183 char * mem = static_cast<char *>(malloc(
184 #else
185 char * mem = static_cast<char *>(alloca(
186 #endif
187 (nParams * sizeof (void *)) +
188 return_size + (nParams * sizeof (largest)) ));
189 void ** uno_args = reinterpret_cast<void **>(mem);
190 void * uno_ret = return_size == 0 ? 0 : (mem + (nParams * sizeof (void *)));
191 largest * uno_args_mem = reinterpret_cast<largest *>
192 (mem + (nParams * sizeof (void *)) + return_size);
194 assert( (0 == nParams) || (nParams == jni->GetArrayLength( jo_args )) );
195 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
197 typelib_MethodParameter const & param = pParams[ nPos ];
198 typelib_TypeDescriptionReference * type = param.pTypeRef;
200 uno_args[ nPos ] = &uno_args_mem[ nPos ];
201 if (typelib_TypeClass_STRUCT == type->eTypeClass ||
202 typelib_TypeClass_EXCEPTION == type->eTypeClass)
204 TypeDescr td( type );
205 if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
206 > sizeof (largest))
207 #ifdef BROKEN_ALLOCA
208 uno_args[ nPos ] = malloc( td.get()->nSize );
209 #else
210 uno_args[ nPos ] = alloca( td.get()->nSize );
211 #endif
214 if (param.bIn)
218 JLocalAutoRef jo_arg(
219 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
220 jni.ensure_no_exception();
221 jvalue java_arg;
222 java_arg.l = jo_arg.get();
223 map_to_uno(
224 jni, uno_args[ nPos ], java_arg, type, 0,
225 false /* no assign */, sal_False != param.bOut,
226 true /* special wrapped integral types */ );
228 catch (...)
230 // cleanup uno in args
231 for ( sal_Int32 n = 0; n < nPos; ++n )
233 typelib_MethodParameter const & p = pParams[ n ];
234 if (p.bIn)
236 uno_type_destructData(
237 uno_args[ n ], p.pTypeRef, 0 );
239 #ifdef BROKEN_ALLOCA
240 if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
241 free( uno_args[ nPos ] );
242 #endif
244 #ifdef BROKEN_ALLOCA
245 free( mem );
246 #endif
247 throw;
252 uno_Any uno_exc_holder;
253 uno_Any * uno_exc = &uno_exc_holder;
254 // call binary uno
255 (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
257 if (0 == uno_exc)
259 // convert out args; destruct uno args
260 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
262 typelib_MethodParameter const & param = pParams[ nPos ];
263 typelib_TypeDescriptionReference * type = param.pTypeRef;
264 if (param.bOut)
268 // get out holder array[ 1 ]
269 JLocalAutoRef jo_out_holder(
270 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
271 jni.ensure_no_exception();
272 jvalue java_arg;
273 java_arg.l = jo_out_holder.get();
274 map_to_java(
275 jni, &java_arg, uno_args[ nPos ], type, 0,
276 true /* in */, true /* out holder */ );
278 catch (...)
280 // cleanup further uno args
281 for ( sal_Int32 n = nPos; n < nParams; ++n )
283 uno_type_destructData(
284 uno_args[ n ], pParams[ n ].pTypeRef, 0 );
285 #ifdef BROKEN_ALLOCA
286 if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
287 free( uno_args[ nPos ] );
288 #endif
290 // cleanup uno return value
291 uno_type_destructData( uno_ret, return_type, 0 );
292 #ifdef BROKEN_ALLOCA
293 free( mem );
294 #endif
295 throw;
298 if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
299 typelib_TypeClass_ENUM != type->eTypeClass) // opt
301 uno_type_destructData( uno_args[ nPos ], type, 0 );
302 #ifdef BROKEN_ALLOCA
303 if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
304 free( uno_args[ nPos ] );
305 #endif
309 if (typelib_TypeClass_VOID != return_type->eTypeClass)
311 // convert uno return value
312 jvalue java_ret;
315 map_to_java(
316 jni, &java_ret, uno_ret, return_type, 0,
317 true /* in */, false /* no out */,
318 true /* special_wrapped_integral_types */ );
320 catch (...)
322 uno_type_destructData( uno_ret, return_type, 0 );
323 #ifdef BROKEN_ALLOCA
324 free( mem );
325 #endif
326 throw;
328 if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
329 typelib_TypeClass_ENUM != return_type->eTypeClass) // opt
331 uno_type_destructData( uno_ret, return_type, 0 );
333 #ifdef BROKEN_ALLOCA
334 free( mem );
335 #endif
336 return java_ret.l;
338 #ifdef BROKEN_ALLOCA
339 free( mem );
340 #endif
341 return 0; // void return
343 else // exception occurred
345 // destruct uno in args
346 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
348 typelib_MethodParameter const & param = pParams[ nPos ];
349 if (param.bIn)
350 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, 0 );
351 #ifdef BROKEN_ALLOCA
352 if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ])
353 free( uno_args[ nPos ] );
354 #endif
357 handle_uno_exc( jni, uno_exc );
358 #ifdef BROKEN_ALLOCA
359 free( mem );
360 #endif
361 return 0;
367 using namespace ::jni_uno;
369 extern "C"
373 SAL_JNI_EXPORT jobject
374 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
375 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
376 jobjectArray jo_args /* may be 0 */ )
378 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
379 JNI_info const * jni_info = bridge->getJniInfo();
380 JNI_context jni(
381 jni_info, jni_env,
382 static_cast< jobject >(
383 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
384 ->machine->getClassLoader()));
386 OUString method_name;
390 method_name = jstring_to_oustring( jni, jo_method );
391 SAL_INFO(
392 "bridges",
393 "java->uno call: " << method_name << " on oid "
394 << jstring_to_oustring(
395 jni,
396 static_cast<jstring>(
397 JLocalAutoRef(
398 jni,
399 jni->GetObjectField(
400 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
401 .get())));
402 // special IQueryInterface.queryInterface()
403 if ( method_name == "queryInterface" )
405 // oid
406 JLocalAutoRef jo_oid(
407 jni, jni->GetObjectField(
408 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
409 // type
410 JLocalAutoRef jo_type(
411 jni, jni->GetObjectArrayElement( jo_args, 0 ) );
412 jni.ensure_no_exception();
414 JLocalAutoRef jo_type_name(
415 jni, jni->GetObjectField(
416 jo_type.get(), jni_info->m_field_Type__typeName ) );
417 if (! jo_type_name.is())
419 throw BridgeRuntimeError(
420 "incomplete type object: no type name!" +
421 jni.get_stack_trace() );
423 OUString type_name(
424 jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
425 JNI_type_info const * info =
426 jni_info->get_type_info( jni, type_name );
427 if (typelib_TypeClass_INTERFACE != info->m_td.get()->eTypeClass)
429 throw BridgeRuntimeError(
430 "queryInterface() call demands an INTERFACE type!" );
432 JNI_interface_type_info const * iface_info =
433 static_cast< JNI_interface_type_info const * >( info );
435 // getRegisteredInterface() already tested in JNI_proxy:
436 // perform queryInterface call on binary uno interface
437 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
438 jni->GetLongField(
439 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
441 uno_Any uno_ret;
442 void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
443 uno_Any uno_exc_holder;
444 uno_Any * uno_exc = &uno_exc_holder;
445 // call binary uno
446 (*pUnoI->pDispatcher)(
447 pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
448 &uno_ret, uno_args, &uno_exc );
449 if (0 == uno_exc)
451 jobject jo_ret = 0;
452 if (typelib_TypeClass_INTERFACE == uno_ret.pType->eTypeClass)
454 uno_Interface * pUnoRet =
455 static_cast<uno_Interface *>(uno_ret.pReserved);
456 if (0 != pUnoRet)
460 jo_ret =
461 bridge->map_to_java( jni, pUnoRet, iface_info );
463 catch (...)
465 uno_any_destruct( &uno_ret, 0 );
466 throw;
470 uno_any_destruct( &uno_ret, 0 );
471 return jo_ret;
473 else
475 bridge->handle_uno_exc( jni, uno_exc );
476 return 0;
480 typelib_InterfaceTypeDescription * td =
481 reinterpret_cast< typelib_InterfaceTypeDescription * >(
482 jni->GetLongField(
483 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
484 uno_Interface * pUnoI =
485 reinterpret_cast< uno_Interface * >(
486 jni->GetLongField(
487 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
489 typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
490 for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
492 // try to avoid getting typedescription as long as possible,
493 // because of a Mutex.acquire() in
494 // typelib_typedescriptionreference_getDescription()
495 typelib_TypeDescriptionReference * member_type =
496 ppAllMembers[ nPos ];
498 // check method_name against fully qualified type_name
499 // of member_type; type_name is of the form
500 // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
501 OUString const & type_name =
502 OUString::unacquired( &member_type->pTypeName );
503 sal_Int32 offset = type_name.indexOf( ':' ) + 2;
504 assert(offset >= 2);
505 assert(offset < type_name.getLength());
506 assert(type_name[offset - 1] == ':' );
507 sal_Int32 remainder = type_name.getLength() - offset;
508 if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass)
510 if ((method_name.getLength() == remainder
511 || (method_name.getLength() < remainder
512 && type_name[offset + method_name.getLength()] == ':'))
513 && type_name.match(method_name, offset))
515 TypeDescr member_td( member_type );
516 typelib_InterfaceMethodTypeDescription * method_td =
517 reinterpret_cast<
518 typelib_InterfaceMethodTypeDescription * >(
519 member_td.get() );
520 return bridge->call_uno(
521 jni, pUnoI, member_td.get(),
522 method_td->pReturnTypeRef,
523 method_td->nParams, method_td->pParams,
524 jo_args );
527 else // attribute
529 assert(
530 typelib_TypeClass_INTERFACE_ATTRIBUTE ==
531 member_type->eTypeClass );
533 if (method_name.getLength() >= 3
534 && (method_name.getLength() - 3 == remainder
535 || (method_name.getLength() - 3 < remainder
536 && type_name[
537 offset + (method_name.getLength() - 3)] == ':'))
538 && method_name[1] == 'e' && method_name[2] == 't'
539 && rtl_ustr_compare_WithLength(
540 type_name.getStr() + offset,
541 method_name.getLength() - 3,
542 method_name.getStr() + 3,
543 method_name.getLength() - 3) == 0)
545 if ('g' == method_name[ 0 ])
547 TypeDescr member_td( member_type );
548 typelib_InterfaceAttributeTypeDescription * attr_td =
549 reinterpret_cast<
550 typelib_InterfaceAttributeTypeDescription * >(
551 member_td.get() );
552 return bridge->call_uno(
553 jni, pUnoI, member_td.get(),
554 attr_td->pAttributeTypeRef,
555 0, 0,
556 jo_args );
558 else if ('s' == method_name[ 0 ])
560 TypeDescr member_td( member_type );
561 typelib_InterfaceAttributeTypeDescription * attr_td =
562 reinterpret_cast<
563 typelib_InterfaceAttributeTypeDescription * >(
564 member_td.get() );
565 if (! attr_td->bReadOnly)
567 typelib_MethodParameter param;
568 param.pTypeRef = attr_td->pAttributeTypeRef;
569 param.bIn = sal_True;
570 param.bOut = sal_False;
571 return bridge->call_uno(
572 jni, pUnoI, member_td.get(),
573 jni_info->m_void_type.getTypeLibType(),
574 1, &param,
575 jo_args );
581 // the thing that should not be... no method info found!
582 throw BridgeRuntimeError(
583 "calling undeclared function on interface "
584 + OUString::unacquired(&td->aBase.pTypeName)
585 + ": " + method_name + jni.get_stack_trace() );
587 catch (const BridgeRuntimeError & err)
589 SAL_WARN(
590 "bridges",
591 "Java calling UNO method " << method_name << ": " << err.m_message);
592 // notify RuntimeException
593 OString cstr_msg(
594 "[jni_uno bridge error] Java calling UNO method "
595 + OUStringToOString(method_name, RTL_TEXTENCODING_JAVA_UTF8) + ": "
596 + OUStringToOString(err.m_message, RTL_TEXTENCODING_JAVA_UTF8));
597 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
598 != 0)
600 assert( false );
602 return 0;
604 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
606 SAL_WARN("bridges", "attaching current thread to java failed");
607 OString cstr_msg(
608 "[jni_uno bridge error] attaching current thread to java failed"
609 + OUStringToOString(
610 jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8));
611 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
612 != 0)
614 assert( false );
616 return 0;
621 SAL_JNI_EXPORT void
622 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
623 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
625 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
626 JNI_info const * jni_info = bridge->getJniInfo();
627 JNI_context jni(
628 jni_info, jni_env,
629 static_cast< jobject >(
630 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
631 ->machine->getClassLoader()));
633 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
634 jni->GetLongField(
635 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
636 typelib_TypeDescription * td =
637 reinterpret_cast< typelib_TypeDescription * >(
638 jni->GetLongField(
639 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
640 SAL_INFO(
641 "bridges",
642 "freeing java uno proxy: "
643 << jstring_to_oustring(
644 jni,
645 static_cast<jstring>(
646 JLocalAutoRef(
647 jni,
648 jni->GetObjectField(
649 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
650 .get())));
651 // revoke from uno env; has already been revoked from java env
652 (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
653 // release receiver
654 (*pUnoI->release)( pUnoI );
655 // release typedescription handle
656 typelib_typedescription_release( td );
657 // release bridge handle
658 bridge->release();
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */