tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / bridges / source / jni_uno / jni_java2uno.cxx
blob449ed982a5d60facdf2a43c353975de045f5ce86
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>
21 #include <sal/log.hxx>
23 #include <algorithm>
24 #include <cassert>
26 #include "jni_bridge.h"
27 #include "jni_helper.h"
28 #include "jniunoenvironmentdata.hxx"
30 #include <com/sun/star/uno/Exception.hpp>
32 namespace jni_uno
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 = nullptr;
42 (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
43 assert( pOid != nullptr );
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 getJniInfo()->m_object_java_env,
53 getJniInfo()->m_method_IEnvironment_getRegisteredInterface, args );
54 jni.ensure_no_exception();
56 if (jo_iface == nullptr) // no registered iface
58 // register uno interface
59 (*m_uno_env->registerInterface)(
60 m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
61 oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
63 // create java and register java proxy
64 jvalue args2[ 8 ];
65 acquire();
66 args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this );
67 (*pUnoI->acquire)( pUnoI );
68 args2[ 1 ].l = getJniInfo()->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 auto * envData = static_cast<jni_uno::JniUnoEnvironmentData *>(
76 m_java_env->pContext);
78 std::unique_lock g(envData->mutex);
79 args2[ 7 ].l = envData->asynchronousFinalizer;
81 jo_iface = jni->CallStaticObjectMethodA(
82 getJniInfo()->m_class_JNI_proxy,
83 getJniInfo()->m_method_JNI_proxy_create, args2 );
84 jni.ensure_no_exception();
87 assert( jo_iface != nullptr );
88 return jo_iface;
92 void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
94 if (uno_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION)
96 #if OSL_DEBUG_LEVEL > 0
97 // append java stack trace to Message member
98 static_cast< css::uno::Exception * >(
99 uno_exc->pData )->Message += jni.get_stack_trace();
100 #endif
101 SAL_INFO(
102 "bridges",
103 "exception occurred java->uno: ["
104 << OUString::unacquired(&uno_exc->pType->pTypeName) << "] "
105 << static_cast<css::uno::Exception const *>(
106 uno_exc->pData)->Message);
107 // signal exception
108 jvalue java_exc;
111 map_to_java(
112 jni, &java_exc, uno_exc->pData, uno_exc->pType, nullptr,
113 true /* in */, false /* no out */ );
115 catch (...)
117 uno_any_destruct( uno_exc, nullptr );
118 throw;
120 uno_any_destruct( uno_exc, nullptr );
122 JLocalAutoRef jo_exc( jni, java_exc.l );
123 jint res = jni->Throw( static_cast<jthrowable>(jo_exc.get()) );
124 if (res != 0)
126 // call toString()
127 JLocalAutoRef jo_descr(
128 jni, jni->CallObjectMethodA(
129 jo_exc.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
130 jni.ensure_no_exception();
131 throw BridgeRuntimeError(
132 "throwing java exception failed: "
133 + jstring_to_oustring( jni, static_cast<jstring>(jo_descr.get()) )
134 + jni.get_stack_trace() );
137 else
139 OUString message(
140 "thrown exception is no uno exception: " +
141 OUString::unacquired( &uno_exc->pType->pTypeName ) +
142 jni.get_stack_trace() );
143 uno_any_destruct( uno_exc, nullptr );
144 throw BridgeRuntimeError( message );
148 namespace {
150 union largest
152 sal_Int64 n;
153 double d;
154 void * p;
155 uno_Any a;
160 jobject Bridge::call_uno(
161 JNI_context const & jni,
162 uno_Interface * pUnoI, typelib_TypeDescription * member_td,
163 typelib_TypeDescriptionReference * return_type,
164 sal_Int32 nParams, typelib_MethodParameter const * pParams,
165 jobjectArray jo_args /* may be 0 */ ) const
167 // return mem
168 sal_Int32 return_size;
169 switch (return_type->eTypeClass) {
170 case typelib_TypeClass_VOID:
171 return_size = 0;
172 break;
174 case typelib_TypeClass_STRUCT:
175 case typelib_TypeClass_EXCEPTION:
176 return_size = std::max(
177 TypeDescr(return_type).get()->nSize,
178 static_cast< sal_Int32 >(sizeof (largest)));
179 break;
181 default:
182 return_size = sizeof (largest);
183 break;
186 char * mem = static_cast<char *>(alloca(
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 ? nullptr : (mem + (nParams * sizeof (void *)));
191 largest * uno_args_mem = reinterpret_cast<largest *>
192 (mem + (nParams * sizeof (void *)) + return_size);
194 assert( (nParams == 0) || (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 (type->eTypeClass == typelib_TypeClass_STRUCT ||
202 type->eTypeClass == typelib_TypeClass_EXCEPTION)
204 TypeDescr td( type );
205 if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
206 > sizeof (largest))
207 uno_args[ nPos ] = alloca( td.get()->nSize );
210 if (param.bIn)
214 JLocalAutoRef jo_arg(
215 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
216 jni.ensure_no_exception();
217 jvalue java_arg;
218 java_arg.l = jo_arg.get();
219 map_to_uno(
220 jni, uno_args[ nPos ], java_arg, type, nullptr,
221 false /* no assign */, param.bOut,
222 true /* special wrapped integral types */ );
224 catch (...)
226 // cleanup uno in args
227 for ( sal_Int32 n = 0; n < nPos; ++n )
229 typelib_MethodParameter const & p = pParams[ n ];
230 if (p.bIn)
232 uno_type_destructData(
233 uno_args[ n ], p.pTypeRef, nullptr );
236 throw;
241 uno_Any uno_exc_holder;
242 uno_Any * uno_exc = &uno_exc_holder;
243 // call binary uno
244 (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
246 if (uno_exc == nullptr)
248 // convert out args; destruct uno args
249 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
251 typelib_MethodParameter const & param = pParams[ nPos ];
252 typelib_TypeDescriptionReference * type = param.pTypeRef;
253 if (param.bOut)
257 // get out holder array[ 1 ]
258 JLocalAutoRef jo_out_holder(
259 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
260 jni.ensure_no_exception();
261 jvalue java_arg;
262 java_arg.l = jo_out_holder.get();
263 map_to_java(
264 jni, &java_arg, uno_args[ nPos ], type, nullptr,
265 true /* in */, true /* out holder */ );
267 catch (...)
269 // cleanup further uno args
270 for ( sal_Int32 n = nPos; n < nParams; ++n )
272 uno_type_destructData(
273 uno_args[ n ], pParams[ n ].pTypeRef, nullptr );
275 // cleanup uno return value
276 uno_type_destructData( uno_ret, return_type, nullptr );
277 throw;
280 if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
281 type->eTypeClass != typelib_TypeClass_ENUM) // opt
283 uno_type_destructData( uno_args[ nPos ], type, nullptr );
287 if (return_type->eTypeClass != typelib_TypeClass_VOID)
289 // convert uno return value
290 jvalue java_ret;
293 map_to_java(
294 jni, &java_ret, uno_ret, return_type, nullptr,
295 true /* in */, false /* no out */,
296 true /* special_wrapped_integral_types */ );
298 catch (...)
300 uno_type_destructData( uno_ret, return_type, nullptr );
301 throw;
303 if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
304 return_type->eTypeClass != typelib_TypeClass_ENUM) // opt
306 uno_type_destructData( uno_ret, return_type, nullptr );
308 return java_ret.l;
310 return nullptr; // void return
312 else // exception occurred
314 // destruct uno in args
315 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
317 typelib_MethodParameter const & param = pParams[ nPos ];
318 if (param.bIn)
319 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, nullptr );
322 handle_uno_exc( jni, uno_exc );
323 return nullptr;
329 using namespace ::jni_uno;
331 extern "C"
335 SAL_JNI_EXPORT jobject
336 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
337 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
338 jobjectArray jo_args /* may be 0 */ )
340 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
341 JNI_info const * jni_info = bridge->getJniInfo();
342 JNI_context jni(
343 jni_info, jni_env,
344 static_cast< jobject >(
345 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
346 ->machine->getClassLoader()));
348 OUString method_name;
352 method_name = jstring_to_oustring( jni, jo_method );
353 SAL_INFO(
354 "bridges",
355 "java->uno call: " << method_name << " on oid "
356 << jstring_to_oustring(
357 jni,
358 static_cast<jstring>(
359 JLocalAutoRef(
360 jni,
361 jni->GetObjectField(
362 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
363 .get())));
364 // special IQueryInterface.queryInterface()
365 if ( method_name == "queryInterface" )
367 // oid
368 JLocalAutoRef jo_oid(
369 jni, jni->GetObjectField(
370 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
371 // type
372 JLocalAutoRef jo_type(
373 jni, jni->GetObjectArrayElement( jo_args, 0 ) );
374 jni.ensure_no_exception();
376 JLocalAutoRef jo_type_name(
377 jni, jni->GetObjectField(
378 jo_type.get(), jni_info->m_field_Type_typeName ) );
379 if (! jo_type_name.is())
381 throw BridgeRuntimeError(
382 "incomplete type object: no type name!" +
383 jni.get_stack_trace() );
385 OUString type_name(
386 jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
387 JNI_type_info const * info =
388 jni_info->get_type_info( jni, type_name );
389 if (info->m_td.get()->eTypeClass != typelib_TypeClass_INTERFACE)
391 throw BridgeRuntimeError(
392 u"queryInterface() call demands an INTERFACE type!"_ustr );
394 JNI_interface_type_info const * iface_info =
395 static_cast< JNI_interface_type_info const * >( info );
397 // getRegisteredInterface() already tested in JNI_proxy:
398 // perform queryInterface call on binary uno interface
399 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
400 jni->GetLongField(
401 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
403 uno_Any uno_ret;
404 void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
405 uno_Any uno_exc_holder;
406 uno_Any * uno_exc = &uno_exc_holder;
407 // call binary uno
408 (*pUnoI->pDispatcher)(
409 pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
410 &uno_ret, uno_args, &uno_exc );
411 if (uno_exc == nullptr)
413 jobject jo_ret = nullptr;
414 if (uno_ret.pType->eTypeClass == typelib_TypeClass_INTERFACE)
416 uno_Interface * pUnoRet =
417 static_cast<uno_Interface *>(uno_ret.pReserved);
418 if (pUnoRet != nullptr)
422 jo_ret =
423 bridge->map_to_java( jni, pUnoRet, iface_info );
425 catch (...)
427 uno_any_destruct( &uno_ret, nullptr );
428 throw;
432 uno_any_destruct( &uno_ret, nullptr );
433 return jo_ret;
435 else
437 bridge->handle_uno_exc( jni, uno_exc );
438 return nullptr;
442 typelib_InterfaceTypeDescription * td =
443 reinterpret_cast< typelib_InterfaceTypeDescription * >(
444 jni->GetLongField(
445 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
446 uno_Interface * pUnoI =
447 reinterpret_cast< uno_Interface * >(
448 jni->GetLongField(
449 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
451 typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
452 for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
454 // try to avoid getting typedescription as long as possible,
455 // because of a Mutex.acquire() in
456 // typelib_typedescriptionreference_getDescription()
457 typelib_TypeDescriptionReference * member_type =
458 ppAllMembers[ nPos ];
460 // check method_name against fully qualified type_name
461 // of member_type; type_name is of the form
462 // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
463 OUString const & type_name =
464 OUString::unacquired( &member_type->pTypeName );
465 sal_Int32 offset = type_name.indexOf( ':' ) + 2;
466 assert(offset >= 2);
467 assert(offset < type_name.getLength());
468 assert(type_name[offset - 1] == ':' );
469 sal_Int32 remainder = type_name.getLength() - offset;
470 if (member_type->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
472 if ((method_name.getLength() == remainder
473 || (method_name.getLength() < remainder
474 && type_name[offset + method_name.getLength()] == ':'))
475 && type_name.match(method_name, offset))
477 TypeDescr member_td( member_type );
478 typelib_InterfaceMethodTypeDescription * method_td =
479 reinterpret_cast<
480 typelib_InterfaceMethodTypeDescription * >(
481 member_td.get() );
482 return bridge->call_uno(
483 jni, pUnoI, member_td.get(),
484 method_td->pReturnTypeRef,
485 method_td->nParams, method_td->pParams,
486 jo_args );
489 else // attribute
491 assert(
492 member_type->eTypeClass ==
493 typelib_TypeClass_INTERFACE_ATTRIBUTE );
495 if (method_name.getLength() >= 3
496 && (method_name.getLength() - 3 == remainder
497 || (method_name.getLength() - 3 < remainder
498 && type_name[
499 offset + (method_name.getLength() - 3)] == ':'))
500 && method_name[1] == 'e' && method_name[2] == 't'
501 && rtl_ustr_compare_WithLength(
502 type_name.getStr() + offset,
503 method_name.getLength() - 3,
504 method_name.getStr() + 3,
505 method_name.getLength() - 3) == 0)
507 if (method_name[ 0 ] == 'g')
509 TypeDescr member_td( member_type );
510 typelib_InterfaceAttributeTypeDescription * attr_td =
511 reinterpret_cast<
512 typelib_InterfaceAttributeTypeDescription * >(
513 member_td.get() );
514 return bridge->call_uno(
515 jni, pUnoI, member_td.get(),
516 attr_td->pAttributeTypeRef,
517 0, nullptr,
518 jo_args );
520 else if (method_name[ 0 ] == 's')
522 TypeDescr member_td( member_type );
523 typelib_InterfaceAttributeTypeDescription * attr_td =
524 reinterpret_cast<
525 typelib_InterfaceAttributeTypeDescription * >(
526 member_td.get() );
527 if (! attr_td->bReadOnly)
529 typelib_MethodParameter param;
530 param.pTypeRef = attr_td->pAttributeTypeRef;
531 param.bIn = true;
532 param.bOut = false;
533 return bridge->call_uno(
534 jni, pUnoI, member_td.get(),
535 jni_info->m_void_type.getTypeLibType(),
536 1, &param,
537 jo_args );
543 // the thing that should not be... no method info found!
544 throw BridgeRuntimeError(
545 "calling undeclared function on interface "
546 + OUString::unacquired(&td->aBase.pTypeName)
547 + ": " + method_name + jni.get_stack_trace() );
549 catch (const BridgeRuntimeError & err)
551 SAL_WARN(
552 "bridges",
553 "Java calling UNO method " << method_name << ": " << err.m_message);
554 // notify RuntimeException
555 OString cstr_msg(
556 "[jni_uno bridge error] Java calling UNO method "
557 + OUStringToOString(method_name, RTL_TEXTENCODING_JAVA_UTF8) + ": "
558 + OUStringToOString(err.m_message, RTL_TEXTENCODING_JAVA_UTF8));
559 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
560 != 0)
562 assert( false );
564 return nullptr;
566 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
568 SAL_WARN("bridges", "attaching current thread to java failed");
569 OString cstr_msg(
570 "[jni_uno bridge error] attaching current thread to java failed"
571 + OUStringToOString(
572 jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8));
573 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
574 != 0)
576 assert( false );
578 return nullptr;
583 SAL_JNI_EXPORT void
584 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
585 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
587 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
588 JNI_info const * jni_info = bridge->getJniInfo();
589 JNI_context jni(
590 jni_info, jni_env,
591 static_cast< jobject >(
592 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
593 ->machine->getClassLoader()));
595 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
596 jni->GetLongField(
597 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
598 typelib_TypeDescription * td =
599 reinterpret_cast< typelib_TypeDescription * >(
600 jni->GetLongField(
601 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
602 SAL_INFO(
603 "bridges",
604 "freeing java uno proxy: "
605 << jstring_to_oustring(
606 jni,
607 static_cast<jstring>(
608 JLocalAutoRef(
609 jni,
610 jni->GetObjectField(
611 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
612 .get())));
613 // revoke from uno env; has already been revoked from java env
614 (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
615 // release receiver
616 (*pUnoI->release)( pUnoI );
617 // release typedescription handle
618 typelib_typedescription_release( td );
619 // release bridge handle
620 bridge->release();
625 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */