Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / bridges / source / jni_uno / jni_java2uno.cxx
blob48219c4fec096c544f2f9b037219db90842a90e5
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 = nullptr;
40 (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
41 assert( pOid != nullptr );
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 (jo_iface == nullptr) // 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( jo_iface != nullptr );
86 return jo_iface;
90 void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
92 if (uno_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION)
94 #if OSL_DEBUG_LEVEL > 0
95 // append java stack trace to Message member
96 static_cast< ::com::sun::star::uno::Exception * >(
97 uno_exc->pData )->Message += jni.get_stack_trace();
98 #endif
99 SAL_INFO(
100 "bridges",
101 "exception occurred java->uno: ["
102 << OUString::unacquired(&uno_exc->pType->pTypeName) << "] "
103 << static_cast<css::uno::Exception const *>(
104 uno_exc->pData)->Message);
105 // signal exception
106 jvalue java_exc;
109 map_to_java(
110 jni, &java_exc, uno_exc->pData, uno_exc->pType, nullptr,
111 true /* in */, false /* no out */ );
113 catch (...)
115 uno_any_destruct( uno_exc, nullptr );
116 throw;
118 uno_any_destruct( uno_exc, nullptr );
120 JLocalAutoRef jo_exc( jni, java_exc.l );
121 jint res = jni->Throw( static_cast<jthrowable>(jo_exc.get()) );
122 if (res != 0)
124 // call toString()
125 JLocalAutoRef jo_descr(
126 jni, jni->CallObjectMethodA(
127 jo_exc.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
128 jni.ensure_no_exception();
129 throw BridgeRuntimeError(
130 "throwing java exception failed: "
131 + jstring_to_oustring( jni, static_cast<jstring>(jo_descr.get()) )
132 + jni.get_stack_trace() );
135 else
137 OUString message(
138 "thrown exception is no uno exception: " +
139 OUString::unacquired( &uno_exc->pType->pTypeName ) +
140 jni.get_stack_trace() );
141 uno_any_destruct( uno_exc, nullptr );
142 throw BridgeRuntimeError( message );
146 union largest
148 sal_Int64 n;
149 double d;
150 void * p;
151 uno_Any a;
155 jobject Bridge::call_uno(
156 JNI_context const & jni,
157 uno_Interface * pUnoI, typelib_TypeDescription * member_td,
158 typelib_TypeDescriptionReference * return_type,
159 sal_Int32 nParams, typelib_MethodParameter const * pParams,
160 jobjectArray jo_args /* may be 0 */ ) const
162 // return mem
163 sal_Int32 return_size;
164 switch (return_type->eTypeClass) {
165 case typelib_TypeClass_VOID:
166 return_size = 0;
167 break;
169 case typelib_TypeClass_STRUCT:
170 case typelib_TypeClass_EXCEPTION:
171 return_size = std::max(
172 TypeDescr(return_type).get()->nSize,
173 static_cast< sal_Int32 >(sizeof (largest)));
174 break;
176 default:
177 return_size = sizeof (largest);
178 break;
181 char * mem = static_cast<char *>(alloca(
182 (nParams * sizeof (void *)) +
183 return_size + (nParams * sizeof (largest)) ));
184 void ** uno_args = reinterpret_cast<void **>(mem);
185 void * uno_ret = return_size == 0 ? nullptr : (mem + (nParams * sizeof (void *)));
186 largest * uno_args_mem = reinterpret_cast<largest *>
187 (mem + (nParams * sizeof (void *)) + return_size);
189 assert( (nParams == 0) || (nParams == jni->GetArrayLength( jo_args )) );
190 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
192 typelib_MethodParameter const & param = pParams[ nPos ];
193 typelib_TypeDescriptionReference * type = param.pTypeRef;
195 uno_args[ nPos ] = &uno_args_mem[ nPos ];
196 if (type->eTypeClass == typelib_TypeClass_STRUCT ||
197 type->eTypeClass == typelib_TypeClass_EXCEPTION)
199 TypeDescr td( type );
200 if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
201 > sizeof (largest))
202 uno_args[ nPos ] = alloca( td.get()->nSize );
205 if (param.bIn)
209 JLocalAutoRef jo_arg(
210 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
211 jni.ensure_no_exception();
212 jvalue java_arg;
213 java_arg.l = jo_arg.get();
214 map_to_uno(
215 jni, uno_args[ nPos ], java_arg, type, nullptr,
216 false /* no assign */, param.bOut,
217 true /* special wrapped integral types */ );
219 catch (...)
221 // cleanup uno in args
222 for ( sal_Int32 n = 0; n < nPos; ++n )
224 typelib_MethodParameter const & p = pParams[ n ];
225 if (p.bIn)
227 uno_type_destructData(
228 uno_args[ n ], p.pTypeRef, nullptr );
231 throw;
236 uno_Any uno_exc_holder;
237 uno_Any * uno_exc = &uno_exc_holder;
238 // call binary uno
239 (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
241 if (uno_exc == nullptr)
243 // convert out args; destruct uno args
244 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
246 typelib_MethodParameter const & param = pParams[ nPos ];
247 typelib_TypeDescriptionReference * type = param.pTypeRef;
248 if (param.bOut)
252 // get out holder array[ 1 ]
253 JLocalAutoRef jo_out_holder(
254 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
255 jni.ensure_no_exception();
256 jvalue java_arg;
257 java_arg.l = jo_out_holder.get();
258 map_to_java(
259 jni, &java_arg, uno_args[ nPos ], type, nullptr,
260 true /* in */, true /* out holder */ );
262 catch (...)
264 // cleanup further uno args
265 for ( sal_Int32 n = nPos; n < nParams; ++n )
267 uno_type_destructData(
268 uno_args[ n ], pParams[ n ].pTypeRef, nullptr );
270 // cleanup uno return value
271 uno_type_destructData( uno_ret, return_type, nullptr );
272 throw;
275 if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
276 type->eTypeClass != typelib_TypeClass_ENUM) // opt
278 uno_type_destructData( uno_args[ nPos ], type, nullptr );
282 if (return_type->eTypeClass != typelib_TypeClass_VOID)
284 // convert uno return value
285 jvalue java_ret;
288 map_to_java(
289 jni, &java_ret, uno_ret, return_type, nullptr,
290 true /* in */, false /* no out */,
291 true /* special_wrapped_integral_types */ );
293 catch (...)
295 uno_type_destructData( uno_ret, return_type, nullptr );
296 throw;
298 if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
299 return_type->eTypeClass != typelib_TypeClass_ENUM) // opt
301 uno_type_destructData( uno_ret, return_type, nullptr );
303 return java_ret.l;
305 return nullptr; // void return
307 else // exception occurred
309 // destruct uno in args
310 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
312 typelib_MethodParameter const & param = pParams[ nPos ];
313 if (param.bIn)
314 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, nullptr );
317 handle_uno_exc( jni, uno_exc );
318 return nullptr;
324 using namespace ::jni_uno;
326 extern "C"
330 SAL_JNI_EXPORT jobject
331 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
332 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
333 jobjectArray jo_args /* may be 0 */ )
335 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
336 JNI_info const * jni_info = bridge->getJniInfo();
337 JNI_context jni(
338 jni_info, jni_env,
339 static_cast< jobject >(
340 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
341 ->machine->getClassLoader()));
343 OUString method_name;
347 method_name = jstring_to_oustring( jni, jo_method );
348 SAL_INFO(
349 "bridges",
350 "java->uno call: " << method_name << " on oid "
351 << jstring_to_oustring(
352 jni,
353 static_cast<jstring>(
354 JLocalAutoRef(
355 jni,
356 jni->GetObjectField(
357 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
358 .get())));
359 // special IQueryInterface.queryInterface()
360 if ( method_name == "queryInterface" )
362 // oid
363 JLocalAutoRef jo_oid(
364 jni, jni->GetObjectField(
365 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
366 // type
367 JLocalAutoRef jo_type(
368 jni, jni->GetObjectArrayElement( jo_args, 0 ) );
369 jni.ensure_no_exception();
371 JLocalAutoRef jo_type_name(
372 jni, jni->GetObjectField(
373 jo_type.get(), jni_info->m_field_Type_typeName ) );
374 if (! jo_type_name.is())
376 throw BridgeRuntimeError(
377 "incomplete type object: no type name!" +
378 jni.get_stack_trace() );
380 OUString type_name(
381 jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
382 JNI_type_info const * info =
383 jni_info->get_type_info( jni, type_name );
384 if (info->m_td.get()->eTypeClass != typelib_TypeClass_INTERFACE)
386 throw BridgeRuntimeError(
387 "queryInterface() call demands an INTERFACE type!" );
389 JNI_interface_type_info const * iface_info =
390 static_cast< JNI_interface_type_info const * >( info );
392 // getRegisteredInterface() already tested in JNI_proxy:
393 // perform queryInterface call on binary uno interface
394 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
395 jni->GetLongField(
396 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
398 uno_Any uno_ret;
399 void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
400 uno_Any uno_exc_holder;
401 uno_Any * uno_exc = &uno_exc_holder;
402 // call binary uno
403 (*pUnoI->pDispatcher)(
404 pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
405 &uno_ret, uno_args, &uno_exc );
406 if (uno_exc == nullptr)
408 jobject jo_ret = nullptr;
409 if (uno_ret.pType->eTypeClass == typelib_TypeClass_INTERFACE)
411 uno_Interface * pUnoRet =
412 static_cast<uno_Interface *>(uno_ret.pReserved);
413 if (pUnoRet != nullptr)
417 jo_ret =
418 bridge->map_to_java( jni, pUnoRet, iface_info );
420 catch (...)
422 uno_any_destruct( &uno_ret, nullptr );
423 throw;
427 uno_any_destruct( &uno_ret, nullptr );
428 return jo_ret;
430 else
432 bridge->handle_uno_exc( jni, uno_exc );
433 return nullptr;
437 typelib_InterfaceTypeDescription * td =
438 reinterpret_cast< typelib_InterfaceTypeDescription * >(
439 jni->GetLongField(
440 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
441 uno_Interface * pUnoI =
442 reinterpret_cast< uno_Interface * >(
443 jni->GetLongField(
444 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
446 typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
447 for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
449 // try to avoid getting typedescription as long as possible,
450 // because of a Mutex.acquire() in
451 // typelib_typedescriptionreference_getDescription()
452 typelib_TypeDescriptionReference * member_type =
453 ppAllMembers[ nPos ];
455 // check method_name against fully qualified type_name
456 // of member_type; type_name is of the form
457 // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
458 OUString const & type_name =
459 OUString::unacquired( &member_type->pTypeName );
460 sal_Int32 offset = type_name.indexOf( ':' ) + 2;
461 assert(offset >= 2);
462 assert(offset < type_name.getLength());
463 assert(type_name[offset - 1] == ':' );
464 sal_Int32 remainder = type_name.getLength() - offset;
465 if (member_type->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
467 if ((method_name.getLength() == remainder
468 || (method_name.getLength() < remainder
469 && type_name[offset + method_name.getLength()] == ':'))
470 && type_name.match(method_name, offset))
472 TypeDescr member_td( member_type );
473 typelib_InterfaceMethodTypeDescription * method_td =
474 reinterpret_cast<
475 typelib_InterfaceMethodTypeDescription * >(
476 member_td.get() );
477 return bridge->call_uno(
478 jni, pUnoI, member_td.get(),
479 method_td->pReturnTypeRef,
480 method_td->nParams, method_td->pParams,
481 jo_args );
484 else // attribute
486 assert(
487 member_type->eTypeClass ==
488 typelib_TypeClass_INTERFACE_ATTRIBUTE );
490 if (method_name.getLength() >= 3
491 && (method_name.getLength() - 3 == remainder
492 || (method_name.getLength() - 3 < remainder
493 && type_name[
494 offset + (method_name.getLength() - 3)] == ':'))
495 && method_name[1] == 'e' && method_name[2] == 't'
496 && rtl_ustr_compare_WithLength(
497 type_name.getStr() + offset,
498 method_name.getLength() - 3,
499 method_name.getStr() + 3,
500 method_name.getLength() - 3) == 0)
502 if (method_name[ 0 ] == 'g')
504 TypeDescr member_td( member_type );
505 typelib_InterfaceAttributeTypeDescription * attr_td =
506 reinterpret_cast<
507 typelib_InterfaceAttributeTypeDescription * >(
508 member_td.get() );
509 return bridge->call_uno(
510 jni, pUnoI, member_td.get(),
511 attr_td->pAttributeTypeRef,
512 0, nullptr,
513 jo_args );
515 else if (method_name[ 0 ] == 's')
517 TypeDescr member_td( member_type );
518 typelib_InterfaceAttributeTypeDescription * attr_td =
519 reinterpret_cast<
520 typelib_InterfaceAttributeTypeDescription * >(
521 member_td.get() );
522 if (! attr_td->bReadOnly)
524 typelib_MethodParameter param;
525 param.pTypeRef = attr_td->pAttributeTypeRef;
526 param.bIn = true;
527 param.bOut = false;
528 return bridge->call_uno(
529 jni, pUnoI, member_td.get(),
530 jni_info->m_void_type.getTypeLibType(),
531 1, &param,
532 jo_args );
538 // the thing that should not be... no method info found!
539 throw BridgeRuntimeError(
540 "calling undeclared function on interface "
541 + OUString::unacquired(&td->aBase.pTypeName)
542 + ": " + method_name + jni.get_stack_trace() );
544 catch (const BridgeRuntimeError & err)
546 SAL_WARN(
547 "bridges",
548 "Java calling UNO method " << method_name << ": " << err.m_message);
549 // notify RuntimeException
550 OString cstr_msg(
551 "[jni_uno bridge error] Java calling UNO method "
552 + OUStringToOString(method_name, RTL_TEXTENCODING_JAVA_UTF8) + ": "
553 + OUStringToOString(err.m_message, RTL_TEXTENCODING_JAVA_UTF8));
554 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
555 != 0)
557 assert( false );
559 return nullptr;
561 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
563 SAL_WARN("bridges", "attaching current thread to java failed");
564 OString cstr_msg(
565 "[jni_uno bridge error] attaching current thread to java failed"
566 + OUStringToOString(
567 jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8));
568 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
569 != 0)
571 assert( false );
573 return nullptr;
578 SAL_JNI_EXPORT void
579 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
580 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
582 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
583 JNI_info const * jni_info = bridge->getJniInfo();
584 JNI_context jni(
585 jni_info, jni_env,
586 static_cast< jobject >(
587 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
588 ->machine->getClassLoader()));
590 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
591 jni->GetLongField(
592 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
593 typelib_TypeDescription * td =
594 reinterpret_cast< typelib_TypeDescription * >(
595 jni->GetLongField(
596 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
597 SAL_INFO(
598 "bridges",
599 "freeing java uno proxy: "
600 << jstring_to_oustring(
601 jni,
602 static_cast<jstring>(
603 JLocalAutoRef(
604 jni,
605 jni->GetObjectField(
606 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
607 .get())));
608 // revoke from uno env; has already been revoked from java env
609 (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
610 // release receiver
611 (*pUnoI->release)( pUnoI );
612 // release typedescription handle
613 typelib_typedescription_release( td );
614 // release bridge handle
615 bridge->release();
620 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */