tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / bridges / source / jni_uno / jni_bridge.cxx
blob8f525b118196691ad35fe896be8daec5dc62d4bd
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 <cassert>
24 #include <memory>
26 #include "jni_bridge.h"
27 #include "jni_helper.h"
28 #include "jniunoenvironmentdata.hxx"
30 #include <jvmaccess/unovirtualmachine.hxx>
31 #include <rtl/ref.hxx>
32 #include <uno/lbnames.h>
34 using namespace ::jni_uno;
36 namespace
38 extern "C"
42 void Mapping_acquire( uno_Mapping * mapping ) noexcept
44 Mapping const * that = static_cast< Mapping const * >( mapping );
45 that->m_bridge->acquire();
49 void Mapping_release( uno_Mapping * mapping ) noexcept
51 Mapping const * that = static_cast< Mapping const * >( mapping );
52 that->m_bridge->release();
56 void Mapping_map_to_uno(
57 uno_Mapping * mapping, void ** ppOut,
58 void * pIn, typelib_InterfaceTypeDescription * td ) noexcept
60 uno_Interface ** ppUnoI = reinterpret_cast<uno_Interface **>(ppOut);
61 jobject javaI = static_cast<jobject>(pIn);
63 static_assert(sizeof (void *) == sizeof (jobject), "must be the same size");
64 assert(ppUnoI != nullptr);
65 assert(td != nullptr);
67 if (javaI == nullptr)
69 if (*ppUnoI != nullptr)
71 uno_Interface * p = *ppUnoI;
72 (*p->release)( p );
73 *ppUnoI = nullptr;
76 else
78 try
80 Bridge const * bridge =
81 static_cast< Mapping const * >( mapping )->m_bridge;
82 JNI_guarded_context jni(
83 bridge->getJniInfo(),
84 (static_cast<jni_uno::JniUnoEnvironmentData *>(
85 bridge->m_java_env->pContext)
86 ->machine));
88 JNI_interface_type_info const * info =
89 static_cast< JNI_interface_type_info const * >(
90 bridge->getJniInfo()->get_type_info(
91 jni, &td->aBase ) );
92 uno_Interface * pUnoI = bridge->map_to_uno( jni, javaI, info );
93 if (*ppUnoI != nullptr)
95 uno_Interface * p = *ppUnoI;
96 (*p->release)( p );
98 *ppUnoI = pUnoI;
100 catch (const BridgeRuntimeError & err)
102 SAL_WARN(
103 "bridges",
104 "ignoring BridgeRuntimeError \"" << err.m_message << "\"");
106 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
108 SAL_WARN("bridges", "attaching current thread to java failed");
114 void Mapping_map_to_java(
115 uno_Mapping * mapping, void ** ppOut,
116 void * pIn, typelib_InterfaceTypeDescription * td ) noexcept
118 jobject * ppJavaI = reinterpret_cast<jobject *>(ppOut);
119 uno_Interface * pUnoI = static_cast<uno_Interface *>(pIn);
121 static_assert(sizeof (void *) == sizeof (jobject), "must be the same size");
122 assert(ppJavaI != nullptr);
123 assert(td != nullptr);
127 if (pUnoI == nullptr)
129 if (*ppJavaI != nullptr)
131 Bridge const * bridge =
132 static_cast< Mapping const * >( mapping )->m_bridge;
133 JNI_guarded_context jni(
134 bridge->getJniInfo(),
135 (static_cast<jni_uno::JniUnoEnvironmentData *>(
136 bridge->m_java_env->pContext)
137 ->machine));
138 jni->DeleteGlobalRef( *ppJavaI );
139 *ppJavaI = nullptr;
142 else
144 Bridge const * bridge =
145 static_cast< Mapping const * >( mapping )->m_bridge;
146 JNI_guarded_context jni(
147 bridge->getJniInfo(),
148 (static_cast<jni_uno::JniUnoEnvironmentData *>(
149 bridge->m_java_env->pContext)
150 ->machine));
152 JNI_interface_type_info const * info =
153 static_cast< JNI_interface_type_info const * >(
154 bridge->getJniInfo()->get_type_info(
155 jni, &td->aBase ) );
156 jobject jlocal = bridge->map_to_java( jni, pUnoI, info );
157 if (*ppJavaI != nullptr)
158 jni->DeleteGlobalRef( *ppJavaI );
159 *ppJavaI = jni->NewGlobalRef( jlocal );
160 jni->DeleteLocalRef( jlocal );
163 catch (const BridgeRuntimeError & err)
165 SAL_WARN(
166 "bridges",
167 "ignoring BridgeRuntimeError \"" << err.m_message << "\"");
169 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
171 SAL_WARN("bridges", "attaching current thread to java failed");
176 void Bridge_free( uno_Mapping * mapping ) noexcept
178 Mapping * that = static_cast< Mapping * >( mapping );
179 delete that->m_bridge;
186 namespace jni_uno
190 void Bridge::acquire() const
192 if (++m_ref != 1)
193 return;
195 if (m_registered_java2uno)
197 uno_Mapping * mapping = const_cast< Mapping * >( &m_java2uno );
198 uno_registerMapping(
199 &mapping, Bridge_free,
200 m_java_env, &m_uno_env->aBase, nullptr );
202 else
204 uno_Mapping * mapping = const_cast< Mapping * >( &m_uno2java );
205 uno_registerMapping(
206 &mapping, Bridge_free,
207 &m_uno_env->aBase, m_java_env, nullptr );
212 void Bridge::release() const
214 if (! --m_ref )
216 uno_revokeMapping(
217 m_registered_java2uno
218 ? const_cast< Mapping * >( &m_java2uno )
219 : const_cast< Mapping * >( &m_uno2java ) );
224 Bridge::Bridge(
225 uno_Environment * java_env, uno_ExtEnvironment * uno_env,
226 bool registered_java2uno )
227 : m_ref( 1 ),
228 m_uno_env( uno_env ),
229 m_java_env( java_env ),
230 m_registered_java2uno( registered_java2uno )
232 assert(m_java_env != nullptr);
233 assert(m_uno_env != nullptr);
235 // uno_initEnvironment (below) cannot report errors directly, so it clears
236 // its pContext upon error to indirectly report errors from here:
237 if (static_cast<jni_uno::JniUnoEnvironmentData *>(m_java_env->pContext)
238 == nullptr)
240 throw BridgeRuntimeError(u"error during JNI-UNO's uno_initEnvironment"_ustr);
243 (*m_uno_env->aBase.acquire)( &m_uno_env->aBase );
244 (*m_java_env->acquire)( m_java_env );
246 // java2uno
247 m_java2uno.acquire = Mapping_acquire;
248 m_java2uno.release = Mapping_release;
249 m_java2uno.mapInterface = Mapping_map_to_uno;
250 m_java2uno.m_bridge = this;
251 // uno2java
252 m_uno2java.acquire = Mapping_acquire;
253 m_uno2java.release = Mapping_release;
254 m_uno2java.mapInterface = Mapping_map_to_java;
255 m_uno2java.m_bridge = this;
259 Bridge::~Bridge()
261 (*m_java_env->release)( m_java_env );
262 (*m_uno_env->aBase.release)( &m_uno_env->aBase );
265 JNI_info const * Bridge::getJniInfo() const {
266 return static_cast<jni_uno::JniUnoEnvironmentData *>(m_java_env->pContext)
267 ->info;
270 void JNI_context::java_exc_occurred() const
272 // !don't rely on JNI_info!
274 JLocalAutoRef jo_exc( *this, m_env->ExceptionOccurred() );
275 m_env->ExceptionClear();
276 assert(jo_exc.is());
277 if (! jo_exc.is())
279 throw BridgeRuntimeError(
280 "java exception occurred, but not available!?" +
281 get_stack_trace() );
284 // call toString(); don't rely on m_jni_info
285 jclass jo_class = m_env->FindClass( "java/lang/Object" );
286 if (m_env->ExceptionCheck())
288 m_env->ExceptionClear();
289 throw BridgeRuntimeError(
290 "cannot get class java.lang.Object!" + get_stack_trace() );
292 JLocalAutoRef jo_Object( *this, jo_class );
293 // method Object.toString()
294 jmethodID method_Object_toString = m_env->GetMethodID(
295 static_cast<jclass>(jo_Object.get()), "toString", "()Ljava/lang/String;" );
296 if (m_env->ExceptionCheck())
298 m_env->ExceptionClear();
299 throw BridgeRuntimeError(
300 "cannot get method id of java.lang.Object.toString()!" +
301 get_stack_trace() );
303 assert(method_Object_toString != nullptr);
305 JLocalAutoRef jo_descr(
306 *this, m_env->CallObjectMethodA(
307 jo_exc.get(), method_Object_toString, nullptr ) );
308 if (m_env->ExceptionCheck()) // no chance at all
310 m_env->ExceptionClear();
311 throw BridgeRuntimeError(
312 "error examining java exception object!" +
313 get_stack_trace() );
316 jsize len = m_env->GetStringLength( static_cast<jstring>(jo_descr.get()) );
317 std::unique_ptr< rtl_mem > ustr_mem(
318 rtl_mem::allocate(
319 sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
320 rtl_uString * ustr = reinterpret_cast<rtl_uString *>(ustr_mem.get());
321 m_env->GetStringRegion( static_cast<jstring>(jo_descr.get()), 0, len, reinterpret_cast<jchar *>(ustr->buffer) );
322 if (m_env->ExceptionCheck())
324 m_env->ExceptionClear();
325 throw BridgeRuntimeError(
326 "invalid java string object!" + get_stack_trace() );
328 ustr->refCount = 1;
329 ustr->length = len;
330 ustr->buffer[ len ] = '\0';
331 OUString message( reinterpret_cast<rtl_uString *>(ustr_mem.release()), SAL_NO_ACQUIRE );
333 throw BridgeRuntimeError( message + get_stack_trace( jo_exc.get() ) );
337 void JNI_context::getClassForName(
338 jclass * classClass, jmethodID * methodForName) const
340 jclass c = m_env->FindClass("java/lang/Class");
341 if (c != nullptr) {
342 *methodForName = m_env->GetStaticMethodID(
343 c, "forName",
344 "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
346 *classClass = c;
350 jclass JNI_context::findClass(
351 char const * name, jclass classClass, jmethodID methodForName,
352 bool inException) const
354 jclass c = nullptr;
355 JLocalAutoRef s(*this, m_env->NewStringUTF(name));
356 if (s.is()) {
357 jvalue a[3];
358 a[0].l = s.get();
359 a[1].z = JNI_FALSE;
360 a[2].l = m_class_loader;
361 c = static_cast< jclass >(
362 m_env->CallStaticObjectMethodA(classClass, methodForName, a));
364 if (!inException) {
365 ensure_no_exception();
367 return c;
371 OUString JNI_context::get_stack_trace( jobject jo_exc ) const
373 JLocalAutoRef jo_JNI_proxy(
374 *this,
375 find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) );
376 if (assert_no_exception())
378 // static method JNI_proxy.get_stack_trace()
379 jmethodID method = m_env->GetStaticMethodID(
380 static_cast<jclass>(jo_JNI_proxy.get()), "get_stack_trace",
381 "(Ljava/lang/Throwable;)Ljava/lang/String;" );
382 if (assert_no_exception() && (method != nullptr))
384 jvalue arg;
385 arg.l = jo_exc;
386 JLocalAutoRef jo_stack_trace(
387 *this, m_env->CallStaticObjectMethodA(
388 static_cast<jclass>(jo_JNI_proxy.get()), method, &arg ) );
389 if (assert_no_exception())
391 jsize len =
392 m_env->GetStringLength( static_cast<jstring>(jo_stack_trace.get()) );
393 std::unique_ptr< rtl_mem > ustr_mem(
394 rtl_mem::allocate(
395 sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
396 rtl_uString * ustr = reinterpret_cast<rtl_uString *>(ustr_mem.get());
397 m_env->GetStringRegion(
398 static_cast<jstring>(jo_stack_trace.get()), 0, len, reinterpret_cast<jchar *>(ustr->buffer) );
399 if (assert_no_exception())
401 ustr->refCount = 1;
402 ustr->length = len;
403 ustr->buffer[ len ] = '\0';
404 return OUString(
405 reinterpret_cast<rtl_uString *>(ustr_mem.release()), SAL_NO_ACQUIRE );
410 return OUString();
415 using namespace ::jni_uno;
417 extern "C" {
419 static void java_env_dispose(uno_Environment * env) {
420 auto * envData
421 = static_cast<jni_uno::JniUnoEnvironmentData *>(env->pContext);
422 if (envData == nullptr) return;
424 jobject async;
426 std::unique_lock g(envData->mutex);
427 async = envData->asynchronousFinalizer;
428 envData->asynchronousFinalizer = nullptr;
430 if (async == nullptr) return;
432 try {
433 JNI_guarded_context jni(envData->info, envData->machine);
434 jni->CallObjectMethodA(
435 async, envData->info->m_method_AsynchronousFinalizer_drain,
436 nullptr);
437 jni.ensure_no_exception();
438 jni->DeleteGlobalRef(async);
439 } catch (const BridgeRuntimeError & e) {
440 SAL_WARN(
441 "bridges",
442 "ignoring BridgeRuntimeError \"" << e.m_message << "\"");
443 } catch (
444 jvmaccess::VirtualMachine::AttachGuard::CreationException &)
446 SAL_WARN(
447 "bridges",
448 ("ignoring jvmaccess::VirtualMachine::AttachGuard"
449 "::CreationException"));
453 static void java_env_disposing(uno_Environment * env) {
454 java_env_dispose(env);
455 delete static_cast<jni_uno::JniUnoEnvironmentData *>(env->pContext);
458 #ifdef DISABLE_DYNLOADING
459 #define uno_initEnvironment java_uno_initEnvironment
460 #endif
463 SAL_DLLPUBLIC_EXPORT void uno_initEnvironment( uno_Environment * java_env ) noexcept
465 try {
466 // JavaComponentLoader::getJavaLoader (in
467 // stoc/source/javaloader/javaloader.cxx) stores a
468 // jvmaccess::UnoVirtualMachine pointer into java_env->pContext; replace
469 // it here with either a pointer to a full JniUnoEnvironmentData upon
470 // success, or with a null pointer upon failure (as this function cannot
471 // directly report back failure, so it uses that way to indirectly
472 // report failure later from within the Bridge ctor):
473 rtl::Reference<jvmaccess::UnoVirtualMachine> vm(
474 static_cast<jvmaccess::UnoVirtualMachine *>(java_env->pContext));
475 java_env->pContext = nullptr;
476 java_env->dispose = java_env_dispose;
477 java_env->environmentDisposing = java_env_disposing;
478 java_env->pExtEnv = nullptr; // no extended support
479 std::unique_ptr<jni_uno::JniUnoEnvironmentData> envData(
480 new jni_uno::JniUnoEnvironmentData(vm));
482 JNI_guarded_context jni(envData->info, envData->machine);
483 JLocalAutoRef ref(
484 jni,
485 jni->NewObject(
486 envData->info->m_class_AsynchronousFinalizer,
487 envData->info->m_ctor_AsynchronousFinalizer));
488 jni.ensure_no_exception();
489 envData->asynchronousFinalizer = jni->NewGlobalRef(ref.get());
490 jni.ensure_no_exception();
492 java_env->pContext = envData.release();
493 } catch (const BridgeRuntimeError & e) {
494 SAL_WARN("bridges", "BridgeRuntimeError \"" << e.m_message << "\"");
495 } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) {
496 SAL_WARN(
497 "bridges",
498 "jvmaccess::VirtualMachine::AttachGuard::CreationException");
502 #ifdef DISABLE_DYNLOADING
503 #define uno_ext_getMapping java_uno_ext_getMapping
504 #endif
507 SAL_DLLPUBLIC_EXPORT void uno_ext_getMapping(
508 uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo ) noexcept
510 assert(ppMapping != nullptr);
511 assert(pFrom != nullptr);
512 assert(pTo != nullptr);
513 if (*ppMapping != nullptr)
515 (*(*ppMapping)->release)( *ppMapping );
516 *ppMapping = nullptr;
519 static_assert(int(JNI_FALSE) == int(false), "must be equal");
520 static_assert(int(JNI_TRUE) == int(true), "must be equal");
521 static_assert(sizeof (jboolean) == sizeof (sal_Bool), "must be the same size");
522 static_assert(sizeof (jchar) == sizeof (sal_Unicode), "must be the same size");
523 static_assert(sizeof (jdouble) == sizeof (double), "must be the same size");
524 static_assert(sizeof (jfloat) == sizeof (float), "must be the same size");
525 static_assert(sizeof (jbyte) == sizeof (sal_Int8), "must be the same size");
526 static_assert(sizeof (jshort) == sizeof (sal_Int16), "must be the same size");
527 static_assert(sizeof (jint) == sizeof (sal_Int32), "must be the same size");
528 static_assert(sizeof (jlong) == sizeof (sal_Int64), "must be the same size");
530 OUString const & from_env_typename =
531 OUString::unacquired( &pFrom->pTypeName );
532 OUString const & to_env_typename =
533 OUString::unacquired( &pTo->pTypeName );
535 uno_Mapping * mapping = nullptr;
539 if ( from_env_typename == UNO_LB_JAVA && to_env_typename == UNO_LB_UNO )
541 Bridge * bridge =
542 new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1
543 mapping = &bridge->m_java2uno;
544 uno_registerMapping(
545 &mapping, Bridge_free,
546 pFrom, &pTo->pExtEnv->aBase, nullptr );
547 // coverity[leaked_storage] - on purpose
549 else if ( from_env_typename == UNO_LB_UNO && to_env_typename == UNO_LB_JAVA )
551 Bridge * bridge =
552 new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1
553 mapping = &bridge->m_uno2java;
554 uno_registerMapping(
555 &mapping, Bridge_free,
556 &pFrom->pExtEnv->aBase, pTo, nullptr );
557 // coverity[leaked_storage] - on purpose
560 catch (const BridgeRuntimeError & err)
562 SAL_WARN("bridges", "BridgeRuntimeError \"" << err.m_message << "\"");
565 *ppMapping = mapping;
570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */