nss: upgrade to release 3.73
[LibreOffice.git] / bridges / source / jni_uno / jni_java2uno.cxx
blobb6c4c6ea9b356a5b3450f3fb370b2880ba2c25c8
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 <sal/alloca.h>
28 #include "jni_bridge.h"
29 #include "jniunoenvironmentdata.hxx"
31 namespace jni_uno
35 jobject Bridge::map_to_java(
36 JNI_context const & jni,
37 uno_Interface * pUnoI, JNI_interface_type_info const * info ) const
39 // get oid
40 rtl_uString * pOid = nullptr;
41 (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
42 assert( pOid != nullptr );
43 OUString oid( pOid, SAL_NO_ACQUIRE );
45 // opt getRegisteredInterface()
46 JLocalAutoRef jo_oid( jni, ustring_to_jstring( jni, oid.pData ) );
47 jvalue args[ 2 ];
48 args[ 0 ].l = jo_oid.get();
49 args[ 1 ].l = info->m_type;
50 jobject jo_iface = jni->CallObjectMethodA(
51 getJniInfo()->m_object_java_env,
52 getJniInfo()->m_method_IEnvironment_getRegisteredInterface, args );
53 jni.ensure_no_exception();
55 if (jo_iface == nullptr) // no registered iface
57 // register uno interface
58 (*m_uno_env->registerInterface)(
59 m_uno_env, reinterpret_cast< void ** >( &pUnoI ),
60 oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );
62 // create java and register java proxy
63 jvalue args2[ 8 ];
64 acquire();
65 args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this );
66 (*pUnoI->acquire)( pUnoI );
67 args2[ 1 ].l = getJniInfo()->m_object_java_env;
68 args2[ 2 ].j = reinterpret_cast< sal_Int64 >( pUnoI );
69 typelib_typedescription_acquire( info->m_td.get() );
70 args2[ 3 ].j = reinterpret_cast< sal_Int64 >( info->m_td.get() );
71 args2[ 4 ].l = info->m_type;
72 args2[ 5 ].l = jo_oid.get();
73 args2[ 6 ].l = info->m_proxy_ctor;
74 auto * envData = static_cast<jni_uno::JniUnoEnvironmentData *>(
75 m_java_env->pContext);
77 osl::MutexGuard g(envData->mutex);
78 args2[ 7 ].l = envData->asynchronousFinalizer;
80 jo_iface = jni->CallStaticObjectMethodA(
81 getJniInfo()->m_class_JNI_proxy,
82 getJniInfo()->m_method_JNI_proxy_create, args2 );
83 jni.ensure_no_exception();
86 assert( jo_iface != nullptr );
87 return jo_iface;
91 void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
93 if (uno_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION)
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, nullptr,
112 true /* in */, false /* no out */ );
114 catch (...)
116 uno_any_destruct( uno_exc, nullptr );
117 throw;
119 uno_any_destruct( uno_exc, nullptr );
121 JLocalAutoRef jo_exc( jni, java_exc.l );
122 jint res = jni->Throw( static_cast<jthrowable>(jo_exc.get()) );
123 if (res != 0)
125 // call toString()
126 JLocalAutoRef jo_descr(
127 jni, jni->CallObjectMethodA(
128 jo_exc.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
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, nullptr );
143 throw BridgeRuntimeError( message );
147 namespace {
149 union largest
151 sal_Int64 n;
152 double d;
153 void * p;
154 uno_Any a;
159 jobject Bridge::call_uno(
160 JNI_context const & jni,
161 uno_Interface * pUnoI, typelib_TypeDescription * member_td,
162 typelib_TypeDescriptionReference * return_type,
163 sal_Int32 nParams, typelib_MethodParameter const * pParams,
164 jobjectArray jo_args /* may be 0 */ ) const
166 // return mem
167 sal_Int32 return_size;
168 switch (return_type->eTypeClass) {
169 case typelib_TypeClass_VOID:
170 return_size = 0;
171 break;
173 case typelib_TypeClass_STRUCT:
174 case typelib_TypeClass_EXCEPTION:
175 return_size = std::max(
176 TypeDescr(return_type).get()->nSize,
177 static_cast< sal_Int32 >(sizeof (largest)));
178 break;
180 default:
181 return_size = sizeof (largest);
182 break;
185 char * mem = static_cast<char *>(alloca(
186 (nParams * sizeof (void *)) +
187 return_size + (nParams * sizeof (largest)) ));
188 void ** uno_args = reinterpret_cast<void **>(mem);
189 void * uno_ret = return_size == 0 ? nullptr : (mem + (nParams * sizeof (void *)));
190 largest * uno_args_mem = reinterpret_cast<largest *>
191 (mem + (nParams * sizeof (void *)) + return_size);
193 assert( (nParams == 0) || (nParams == jni->GetArrayLength( jo_args )) );
194 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
196 typelib_MethodParameter const & param = pParams[ nPos ];
197 typelib_TypeDescriptionReference * type = param.pTypeRef;
199 uno_args[ nPos ] = &uno_args_mem[ nPos ];
200 if (type->eTypeClass == typelib_TypeClass_STRUCT ||
201 type->eTypeClass == typelib_TypeClass_EXCEPTION)
203 TypeDescr td( type );
204 if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
205 > sizeof (largest))
206 uno_args[ nPos ] = alloca( td.get()->nSize );
209 if (param.bIn)
213 JLocalAutoRef jo_arg(
214 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
215 jni.ensure_no_exception();
216 jvalue java_arg;
217 java_arg.l = jo_arg.get();
218 map_to_uno(
219 jni, uno_args[ nPos ], java_arg, type, nullptr,
220 false /* no assign */, param.bOut,
221 true /* special wrapped integral types */ );
223 catch (...)
225 // cleanup uno in args
226 for ( sal_Int32 n = 0; n < nPos; ++n )
228 typelib_MethodParameter const & p = pParams[ n ];
229 if (p.bIn)
231 uno_type_destructData(
232 uno_args[ n ], p.pTypeRef, nullptr );
235 throw;
240 uno_Any uno_exc_holder;
241 uno_Any * uno_exc = &uno_exc_holder;
242 // call binary uno
243 (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
245 if (uno_exc == nullptr)
247 // convert out args; destruct uno args
248 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
250 typelib_MethodParameter const & param = pParams[ nPos ];
251 typelib_TypeDescriptionReference * type = param.pTypeRef;
252 if (param.bOut)
256 // get out holder array[ 1 ]
257 JLocalAutoRef jo_out_holder(
258 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
259 jni.ensure_no_exception();
260 jvalue java_arg;
261 java_arg.l = jo_out_holder.get();
262 map_to_java(
263 jni, &java_arg, uno_args[ nPos ], type, nullptr,
264 true /* in */, true /* out holder */ );
266 catch (...)
268 // cleanup further uno args
269 for ( sal_Int32 n = nPos; n < nParams; ++n )
271 uno_type_destructData(
272 uno_args[ n ], pParams[ n ].pTypeRef, nullptr );
274 // cleanup uno return value
275 uno_type_destructData( uno_ret, return_type, nullptr );
276 throw;
279 if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
280 type->eTypeClass != typelib_TypeClass_ENUM) // opt
282 uno_type_destructData( uno_args[ nPos ], type, nullptr );
286 if (return_type->eTypeClass != typelib_TypeClass_VOID)
288 // convert uno return value
289 jvalue java_ret;
292 map_to_java(
293 jni, &java_ret, uno_ret, return_type, nullptr,
294 true /* in */, false /* no out */,
295 true /* special_wrapped_integral_types */ );
297 catch (...)
299 uno_type_destructData( uno_ret, return_type, nullptr );
300 throw;
302 if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
303 return_type->eTypeClass != typelib_TypeClass_ENUM) // opt
305 uno_type_destructData( uno_ret, return_type, nullptr );
307 return java_ret.l;
309 return nullptr; // void return
311 else // exception occurred
313 // destruct uno in args
314 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
316 typelib_MethodParameter const & param = pParams[ nPos ];
317 if (param.bIn)
318 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, nullptr );
321 handle_uno_exc( jni, uno_exc );
322 return nullptr;
328 using namespace ::jni_uno;
330 extern "C"
334 SAL_JNI_EXPORT jobject
335 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
336 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
337 jobjectArray jo_args /* may be 0 */ )
339 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
340 JNI_info const * jni_info = bridge->getJniInfo();
341 JNI_context jni(
342 jni_info, jni_env,
343 static_cast< jobject >(
344 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
345 ->machine->getClassLoader()));
347 OUString method_name;
351 method_name = jstring_to_oustring( jni, jo_method );
352 SAL_INFO(
353 "bridges",
354 "java->uno call: " << method_name << " on oid "
355 << jstring_to_oustring(
356 jni,
357 static_cast<jstring>(
358 JLocalAutoRef(
359 jni,
360 jni->GetObjectField(
361 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
362 .get())));
363 // special IQueryInterface.queryInterface()
364 if ( method_name == "queryInterface" )
366 // oid
367 JLocalAutoRef jo_oid(
368 jni, jni->GetObjectField(
369 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
370 // type
371 JLocalAutoRef jo_type(
372 jni, jni->GetObjectArrayElement( jo_args, 0 ) );
373 jni.ensure_no_exception();
375 JLocalAutoRef jo_type_name(
376 jni, jni->GetObjectField(
377 jo_type.get(), jni_info->m_field_Type_typeName ) );
378 if (! jo_type_name.is())
380 throw BridgeRuntimeError(
381 "incomplete type object: no type name!" +
382 jni.get_stack_trace() );
384 OUString type_name(
385 jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
386 JNI_type_info const * info =
387 jni_info->get_type_info( jni, type_name );
388 if (info->m_td.get()->eTypeClass != typelib_TypeClass_INTERFACE)
390 throw BridgeRuntimeError(
391 "queryInterface() call demands an INTERFACE type!" );
393 JNI_interface_type_info const * iface_info =
394 static_cast< JNI_interface_type_info const * >( info );
396 // getRegisteredInterface() already tested in JNI_proxy:
397 // perform queryInterface call on binary uno interface
398 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
399 jni->GetLongField(
400 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
402 uno_Any uno_ret;
403 void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
404 uno_Any uno_exc_holder;
405 uno_Any * uno_exc = &uno_exc_holder;
406 // call binary uno
407 (*pUnoI->pDispatcher)(
408 pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
409 &uno_ret, uno_args, &uno_exc );
410 if (uno_exc == nullptr)
412 jobject jo_ret = nullptr;
413 if (uno_ret.pType->eTypeClass == typelib_TypeClass_INTERFACE)
415 uno_Interface * pUnoRet =
416 static_cast<uno_Interface *>(uno_ret.pReserved);
417 if (pUnoRet != nullptr)
421 jo_ret =
422 bridge->map_to_java( jni, pUnoRet, iface_info );
424 catch (...)
426 uno_any_destruct( &uno_ret, nullptr );
427 throw;
431 uno_any_destruct( &uno_ret, nullptr );
432 return jo_ret;
434 else
436 bridge->handle_uno_exc( jni, uno_exc );
437 return nullptr;
441 typelib_InterfaceTypeDescription * td =
442 reinterpret_cast< typelib_InterfaceTypeDescription * >(
443 jni->GetLongField(
444 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
445 uno_Interface * pUnoI =
446 reinterpret_cast< uno_Interface * >(
447 jni->GetLongField(
448 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
450 typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
451 for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
453 // try to avoid getting typedescription as long as possible,
454 // because of a Mutex.acquire() in
455 // typelib_typedescriptionreference_getDescription()
456 typelib_TypeDescriptionReference * member_type =
457 ppAllMembers[ nPos ];
459 // check method_name against fully qualified type_name
460 // of member_type; type_name is of the form
461 // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
462 OUString const & type_name =
463 OUString::unacquired( &member_type->pTypeName );
464 sal_Int32 offset = type_name.indexOf( ':' ) + 2;
465 assert(offset >= 2);
466 assert(offset < type_name.getLength());
467 assert(type_name[offset - 1] == ':' );
468 sal_Int32 remainder = type_name.getLength() - offset;
469 if (member_type->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
471 if ((method_name.getLength() == remainder
472 || (method_name.getLength() < remainder
473 && type_name[offset + method_name.getLength()] == ':'))
474 && type_name.match(method_name, offset))
476 TypeDescr member_td( member_type );
477 typelib_InterfaceMethodTypeDescription * method_td =
478 reinterpret_cast<
479 typelib_InterfaceMethodTypeDescription * >(
480 member_td.get() );
481 return bridge->call_uno(
482 jni, pUnoI, member_td.get(),
483 method_td->pReturnTypeRef,
484 method_td->nParams, method_td->pParams,
485 jo_args );
488 else // attribute
490 assert(
491 member_type->eTypeClass ==
492 typelib_TypeClass_INTERFACE_ATTRIBUTE );
494 if (method_name.getLength() >= 3
495 && (method_name.getLength() - 3 == remainder
496 || (method_name.getLength() - 3 < remainder
497 && type_name[
498 offset + (method_name.getLength() - 3)] == ':'))
499 && method_name[1] == 'e' && method_name[2] == 't'
500 && rtl_ustr_compare_WithLength(
501 type_name.getStr() + offset,
502 method_name.getLength() - 3,
503 method_name.getStr() + 3,
504 method_name.getLength() - 3) == 0)
506 if (method_name[ 0 ] == 'g')
508 TypeDescr member_td( member_type );
509 typelib_InterfaceAttributeTypeDescription * attr_td =
510 reinterpret_cast<
511 typelib_InterfaceAttributeTypeDescription * >(
512 member_td.get() );
513 return bridge->call_uno(
514 jni, pUnoI, member_td.get(),
515 attr_td->pAttributeTypeRef,
516 0, nullptr,
517 jo_args );
519 else if (method_name[ 0 ] == 's')
521 TypeDescr member_td( member_type );
522 typelib_InterfaceAttributeTypeDescription * attr_td =
523 reinterpret_cast<
524 typelib_InterfaceAttributeTypeDescription * >(
525 member_td.get() );
526 if (! attr_td->bReadOnly)
528 typelib_MethodParameter param;
529 param.pTypeRef = attr_td->pAttributeTypeRef;
530 param.bIn = true;
531 param.bOut = false;
532 return bridge->call_uno(
533 jni, pUnoI, member_td.get(),
534 jni_info->m_void_type.getTypeLibType(),
535 1, &param,
536 jo_args );
542 // the thing that should not be... no method info found!
543 throw BridgeRuntimeError(
544 "calling undeclared function on interface "
545 + OUString::unacquired(&td->aBase.pTypeName)
546 + ": " + method_name + jni.get_stack_trace() );
548 catch (const BridgeRuntimeError & err)
550 SAL_WARN(
551 "bridges",
552 "Java calling UNO method " << method_name << ": " << err.m_message);
553 // notify RuntimeException
554 OString cstr_msg(
555 "[jni_uno bridge error] Java calling UNO method "
556 + OUStringToOString(method_name, RTL_TEXTENCODING_JAVA_UTF8) + ": "
557 + OUStringToOString(err.m_message, RTL_TEXTENCODING_JAVA_UTF8));
558 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
559 != 0)
561 assert( false );
563 return nullptr;
565 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
567 SAL_WARN("bridges", "attaching current thread to java failed");
568 OString cstr_msg(
569 "[jni_uno bridge error] attaching current thread to java failed"
570 + OUStringToOString(
571 jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8));
572 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
573 != 0)
575 assert( false );
577 return nullptr;
582 SAL_JNI_EXPORT void
583 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
584 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
586 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
587 JNI_info const * jni_info = bridge->getJniInfo();
588 JNI_context jni(
589 jni_info, jni_env,
590 static_cast< jobject >(
591 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
592 ->machine->getClassLoader()));
594 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
595 jni->GetLongField(
596 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
597 typelib_TypeDescription * td =
598 reinterpret_cast< typelib_TypeDescription * >(
599 jni->GetLongField(
600 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
601 SAL_INFO(
602 "bridges",
603 "freeing java uno proxy: "
604 << jstring_to_oustring(
605 jni,
606 static_cast<jstring>(
607 JLocalAutoRef(
608 jni,
609 jni->GetObjectField(
610 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
611 .get())));
612 // revoke from uno env; has already been revoked from java env
613 (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
614 // release receiver
615 (*pUnoI->release)( pUnoI );
616 // release typedescription handle
617 typelib_typedescription_release( td );
618 // release bridge handle
619 bridge->release();
624 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */