bump product version to 6.3.0.0.beta1
[LibreOffice.git] / bridges / source / jni_uno / jni_java2uno.cxx
blob4092933be49ff30c8decbef9254841ec6c00a907
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 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 char * mem = static_cast<char *>(alloca(
183 (nParams * sizeof (void *)) +
184 return_size + (nParams * sizeof (largest)) ));
185 void ** uno_args = reinterpret_cast<void **>(mem);
186 void * uno_ret = return_size == 0 ? nullptr : (mem + (nParams * sizeof (void *)));
187 largest * uno_args_mem = reinterpret_cast<largest *>
188 (mem + (nParams * sizeof (void *)) + return_size);
190 assert( (nParams == 0) || (nParams == jni->GetArrayLength( jo_args )) );
191 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
193 typelib_MethodParameter const & param = pParams[ nPos ];
194 typelib_TypeDescriptionReference * type = param.pTypeRef;
196 uno_args[ nPos ] = &uno_args_mem[ nPos ];
197 if (type->eTypeClass == typelib_TypeClass_STRUCT ||
198 type->eTypeClass == typelib_TypeClass_EXCEPTION)
200 TypeDescr td( type );
201 if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
202 > sizeof (largest))
203 uno_args[ nPos ] = alloca( td.get()->nSize );
206 if (param.bIn)
210 JLocalAutoRef jo_arg(
211 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
212 jni.ensure_no_exception();
213 jvalue java_arg;
214 java_arg.l = jo_arg.get();
215 map_to_uno(
216 jni, uno_args[ nPos ], java_arg, type, nullptr,
217 false /* no assign */, param.bOut,
218 true /* special wrapped integral types */ );
220 catch (...)
222 // cleanup uno in args
223 for ( sal_Int32 n = 0; n < nPos; ++n )
225 typelib_MethodParameter const & p = pParams[ n ];
226 if (p.bIn)
228 uno_type_destructData(
229 uno_args[ n ], p.pTypeRef, nullptr );
232 throw;
237 uno_Any uno_exc_holder;
238 uno_Any * uno_exc = &uno_exc_holder;
239 // call binary uno
240 (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );
242 if (uno_exc == nullptr)
244 // convert out args; destruct uno args
245 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
247 typelib_MethodParameter const & param = pParams[ nPos ];
248 typelib_TypeDescriptionReference * type = param.pTypeRef;
249 if (param.bOut)
253 // get out holder array[ 1 ]
254 JLocalAutoRef jo_out_holder(
255 jni, jni->GetObjectArrayElement( jo_args, nPos ) );
256 jni.ensure_no_exception();
257 jvalue java_arg;
258 java_arg.l = jo_out_holder.get();
259 map_to_java(
260 jni, &java_arg, uno_args[ nPos ], type, nullptr,
261 true /* in */, true /* out holder */ );
263 catch (...)
265 // cleanup further uno args
266 for ( sal_Int32 n = nPos; n < nParams; ++n )
268 uno_type_destructData(
269 uno_args[ n ], pParams[ n ].pTypeRef, nullptr );
271 // cleanup uno return value
272 uno_type_destructData( uno_ret, return_type, nullptr );
273 throw;
276 if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
277 type->eTypeClass != typelib_TypeClass_ENUM) // opt
279 uno_type_destructData( uno_args[ nPos ], type, nullptr );
283 if (return_type->eTypeClass != typelib_TypeClass_VOID)
285 // convert uno return value
286 jvalue java_ret;
289 map_to_java(
290 jni, &java_ret, uno_ret, return_type, nullptr,
291 true /* in */, false /* no out */,
292 true /* special_wrapped_integral_types */ );
294 catch (...)
296 uno_type_destructData( uno_ret, return_type, nullptr );
297 throw;
299 if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
300 return_type->eTypeClass != typelib_TypeClass_ENUM) // opt
302 uno_type_destructData( uno_ret, return_type, nullptr );
304 return java_ret.l;
306 return nullptr; // void return
308 else // exception occurred
310 // destruct uno in args
311 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
313 typelib_MethodParameter const & param = pParams[ nPos ];
314 if (param.bIn)
315 uno_type_destructData( uno_args[ nPos ], param.pTypeRef, nullptr );
318 handle_uno_exc( jni, uno_exc );
319 return nullptr;
325 using namespace ::jni_uno;
327 extern "C"
331 SAL_JNI_EXPORT jobject
332 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
333 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
334 jobjectArray jo_args /* may be 0 */ )
336 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
337 JNI_info const * jni_info = bridge->getJniInfo();
338 JNI_context jni(
339 jni_info, jni_env,
340 static_cast< jobject >(
341 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
342 ->machine->getClassLoader()));
344 OUString method_name;
348 method_name = jstring_to_oustring( jni, jo_method );
349 SAL_INFO(
350 "bridges",
351 "java->uno call: " << method_name << " on oid "
352 << jstring_to_oustring(
353 jni,
354 static_cast<jstring>(
355 JLocalAutoRef(
356 jni,
357 jni->GetObjectField(
358 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
359 .get())));
360 // special IQueryInterface.queryInterface()
361 if ( method_name == "queryInterface" )
363 // oid
364 JLocalAutoRef jo_oid(
365 jni, jni->GetObjectField(
366 jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
367 // type
368 JLocalAutoRef jo_type(
369 jni, jni->GetObjectArrayElement( jo_args, 0 ) );
370 jni.ensure_no_exception();
372 JLocalAutoRef jo_type_name(
373 jni, jni->GetObjectField(
374 jo_type.get(), jni_info->m_field_Type_typeName ) );
375 if (! jo_type_name.is())
377 throw BridgeRuntimeError(
378 "incomplete type object: no type name!" +
379 jni.get_stack_trace() );
381 OUString type_name(
382 jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
383 JNI_type_info const * info =
384 jni_info->get_type_info( jni, type_name );
385 if (info->m_td.get()->eTypeClass != typelib_TypeClass_INTERFACE)
387 throw BridgeRuntimeError(
388 "queryInterface() call demands an INTERFACE type!" );
390 JNI_interface_type_info const * iface_info =
391 static_cast< JNI_interface_type_info const * >( info );
393 // getRegisteredInterface() already tested in JNI_proxy:
394 // perform queryInterface call on binary uno interface
395 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
396 jni->GetLongField(
397 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
399 uno_Any uno_ret;
400 void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
401 uno_Any uno_exc_holder;
402 uno_Any * uno_exc = &uno_exc_holder;
403 // call binary uno
404 (*pUnoI->pDispatcher)(
405 pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
406 &uno_ret, uno_args, &uno_exc );
407 if (uno_exc == nullptr)
409 jobject jo_ret = nullptr;
410 if (uno_ret.pType->eTypeClass == typelib_TypeClass_INTERFACE)
412 uno_Interface * pUnoRet =
413 static_cast<uno_Interface *>(uno_ret.pReserved);
414 if (pUnoRet != nullptr)
418 jo_ret =
419 bridge->map_to_java( jni, pUnoRet, iface_info );
421 catch (...)
423 uno_any_destruct( &uno_ret, nullptr );
424 throw;
428 uno_any_destruct( &uno_ret, nullptr );
429 return jo_ret;
431 else
433 bridge->handle_uno_exc( jni, uno_exc );
434 return nullptr;
438 typelib_InterfaceTypeDescription * td =
439 reinterpret_cast< typelib_InterfaceTypeDescription * >(
440 jni->GetLongField(
441 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
442 uno_Interface * pUnoI =
443 reinterpret_cast< uno_Interface * >(
444 jni->GetLongField(
445 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
447 typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
448 for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
450 // try to avoid getting typedescription as long as possible,
451 // because of a Mutex.acquire() in
452 // typelib_typedescriptionreference_getDescription()
453 typelib_TypeDescriptionReference * member_type =
454 ppAllMembers[ nPos ];
456 // check method_name against fully qualified type_name
457 // of member_type; type_name is of the form
458 // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
459 OUString const & type_name =
460 OUString::unacquired( &member_type->pTypeName );
461 sal_Int32 offset = type_name.indexOf( ':' ) + 2;
462 assert(offset >= 2);
463 assert(offset < type_name.getLength());
464 assert(type_name[offset - 1] == ':' );
465 sal_Int32 remainder = type_name.getLength() - offset;
466 if (member_type->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
468 if ((method_name.getLength() == remainder
469 || (method_name.getLength() < remainder
470 && type_name[offset + method_name.getLength()] == ':'))
471 && type_name.match(method_name, offset))
473 TypeDescr member_td( member_type );
474 typelib_InterfaceMethodTypeDescription * method_td =
475 reinterpret_cast<
476 typelib_InterfaceMethodTypeDescription * >(
477 member_td.get() );
478 return bridge->call_uno(
479 jni, pUnoI, member_td.get(),
480 method_td->pReturnTypeRef,
481 method_td->nParams, method_td->pParams,
482 jo_args );
485 else // attribute
487 assert(
488 member_type->eTypeClass ==
489 typelib_TypeClass_INTERFACE_ATTRIBUTE );
491 if (method_name.getLength() >= 3
492 && (method_name.getLength() - 3 == remainder
493 || (method_name.getLength() - 3 < remainder
494 && type_name[
495 offset + (method_name.getLength() - 3)] == ':'))
496 && method_name[1] == 'e' && method_name[2] == 't'
497 && rtl_ustr_compare_WithLength(
498 type_name.getStr() + offset,
499 method_name.getLength() - 3,
500 method_name.getStr() + 3,
501 method_name.getLength() - 3) == 0)
503 if (method_name[ 0 ] == 'g')
505 TypeDescr member_td( member_type );
506 typelib_InterfaceAttributeTypeDescription * attr_td =
507 reinterpret_cast<
508 typelib_InterfaceAttributeTypeDescription * >(
509 member_td.get() );
510 return bridge->call_uno(
511 jni, pUnoI, member_td.get(),
512 attr_td->pAttributeTypeRef,
513 0, nullptr,
514 jo_args );
516 else if (method_name[ 0 ] == 's')
518 TypeDescr member_td( member_type );
519 typelib_InterfaceAttributeTypeDescription * attr_td =
520 reinterpret_cast<
521 typelib_InterfaceAttributeTypeDescription * >(
522 member_td.get() );
523 if (! attr_td->bReadOnly)
525 typelib_MethodParameter param;
526 param.pTypeRef = attr_td->pAttributeTypeRef;
527 param.bIn = true;
528 param.bOut = false;
529 return bridge->call_uno(
530 jni, pUnoI, member_td.get(),
531 jni_info->m_void_type.getTypeLibType(),
532 1, &param,
533 jo_args );
539 // the thing that should not be... no method info found!
540 throw BridgeRuntimeError(
541 "calling undeclared function on interface "
542 + OUString::unacquired(&td->aBase.pTypeName)
543 + ": " + method_name + jni.get_stack_trace() );
545 catch (const BridgeRuntimeError & err)
547 SAL_WARN(
548 "bridges",
549 "Java calling UNO method " << method_name << ": " << err.m_message);
550 // notify RuntimeException
551 OString cstr_msg(
552 "[jni_uno bridge error] Java calling UNO method "
553 + OUStringToOString(method_name, RTL_TEXTENCODING_JAVA_UTF8) + ": "
554 + OUStringToOString(err.m_message, RTL_TEXTENCODING_JAVA_UTF8));
555 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
556 != 0)
558 assert( false );
560 return nullptr;
562 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
564 SAL_WARN("bridges", "attaching current thread to java failed");
565 OString cstr_msg(
566 "[jni_uno bridge error] attaching current thread to java failed"
567 + OUStringToOString(
568 jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8));
569 if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
570 != 0)
572 assert( false );
574 return nullptr;
579 SAL_JNI_EXPORT void
580 JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
581 JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
583 Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
584 JNI_info const * jni_info = bridge->getJniInfo();
585 JNI_context jni(
586 jni_info, jni_env,
587 static_cast< jobject >(
588 static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
589 ->machine->getClassLoader()));
591 uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
592 jni->GetLongField(
593 jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
594 typelib_TypeDescription * td =
595 reinterpret_cast< typelib_TypeDescription * >(
596 jni->GetLongField(
597 jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
598 SAL_INFO(
599 "bridges",
600 "freeing java uno proxy: "
601 << jstring_to_oustring(
602 jni,
603 static_cast<jstring>(
604 JLocalAutoRef(
605 jni,
606 jni->GetObjectField(
607 jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
608 .get())));
609 // revoke from uno env; has already been revoked from java env
610 (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
611 // release receiver
612 (*pUnoI->release)( pUnoI );
613 // release typedescription handle
614 typelib_typedescription_release( td );
615 // release bridge handle
616 bridge->release();
621 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */