1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
26 #include "jni_bridge.h"
27 #include "jniunoenvironmentdata.hxx"
29 #include <jvmaccess/unovirtualmachine.hxx>
30 #include <rtl/ref.hxx>
31 #include <rtl/strbuf.hxx>
32 #include <uno/lbnames.h>
34 using namespace ::osl
;
35 using namespace ::jni_uno
;
43 void Mapping_acquire( uno_Mapping
* mapping
)
46 Mapping
const * that
= static_cast< Mapping
const * >( mapping
);
47 that
->m_bridge
->acquire();
51 void Mapping_release( uno_Mapping
* mapping
)
54 Mapping
const * that
= static_cast< Mapping
const * >( mapping
);
55 that
->m_bridge
->release();
59 void Mapping_map_to_uno(
60 uno_Mapping
* mapping
, void ** ppOut
,
61 void * pIn
, typelib_InterfaceTypeDescription
* td
)
64 uno_Interface
** ppUnoI
= reinterpret_cast<uno_Interface
**>(ppOut
);
65 jobject javaI
= static_cast<jobject
>(pIn
);
67 static_assert(sizeof (void *) == sizeof (jobject
), "must be the same size");
68 assert(ppUnoI
!= nullptr);
69 assert(td
!= nullptr);
73 if (*ppUnoI
!= nullptr)
75 uno_Interface
* p
= *ppUnoI
;
84 Bridge
const * bridge
=
85 static_cast< Mapping
const * >( mapping
)->m_bridge
;
86 JNI_guarded_context
jni(
88 (static_cast<jni_uno::JniUnoEnvironmentData
*>(
89 bridge
->m_java_env
->pContext
)
92 JNI_interface_type_info
const * info
=
93 static_cast< JNI_interface_type_info
const * >(
94 bridge
->getJniInfo()->get_type_info(
96 uno_Interface
* pUnoI
= bridge
->map_to_uno( jni
, javaI
, info
);
97 if (*ppUnoI
!= nullptr)
99 uno_Interface
* p
= *ppUnoI
;
104 catch (const BridgeRuntimeError
& err
)
108 "ignoring BridgeRuntimeError \"" << err
.m_message
<< "\"");
110 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
112 SAL_WARN("bridges", "attaching current thread to java failed");
118 void Mapping_map_to_java(
119 uno_Mapping
* mapping
, void ** ppOut
,
120 void * pIn
, typelib_InterfaceTypeDescription
* td
)
123 jobject
* ppJavaI
= reinterpret_cast<jobject
*>(ppOut
);
124 uno_Interface
* pUnoI
= static_cast<uno_Interface
*>(pIn
);
126 static_assert(sizeof (void *) == sizeof (jobject
), "must be the same size");
127 assert(ppJavaI
!= nullptr);
128 assert(td
!= nullptr);
132 if (pUnoI
== nullptr)
134 if (*ppJavaI
!= nullptr)
136 Bridge
const * bridge
=
137 static_cast< Mapping
const * >( mapping
)->m_bridge
;
138 JNI_guarded_context
jni(
139 bridge
->getJniInfo(),
140 (static_cast<jni_uno::JniUnoEnvironmentData
*>(
141 bridge
->m_java_env
->pContext
)
143 jni
->DeleteGlobalRef( *ppJavaI
);
149 Bridge
const * bridge
=
150 static_cast< Mapping
const * >( mapping
)->m_bridge
;
151 JNI_guarded_context
jni(
152 bridge
->getJniInfo(),
153 (static_cast<jni_uno::JniUnoEnvironmentData
*>(
154 bridge
->m_java_env
->pContext
)
157 JNI_interface_type_info
const * info
=
158 static_cast< JNI_interface_type_info
const * >(
159 bridge
->getJniInfo()->get_type_info(
161 jobject jlocal
= bridge
->map_to_java( jni
, pUnoI
, info
);
162 if (*ppJavaI
!= nullptr)
163 jni
->DeleteGlobalRef( *ppJavaI
);
164 *ppJavaI
= jni
->NewGlobalRef( jlocal
);
165 jni
->DeleteLocalRef( jlocal
);
168 catch (const BridgeRuntimeError
& err
)
172 "ignoring BridgeRuntimeError \"" << err
.m_message
<< "\"");
174 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
176 SAL_WARN("bridges", "attaching current thread to java failed");
181 void Bridge_free( uno_Mapping
* mapping
)
184 Mapping
* that
= static_cast< Mapping
* >( mapping
);
185 delete that
->m_bridge
;
196 void Bridge::acquire() const
200 if (m_registered_java2uno
)
202 uno_Mapping
* mapping
= const_cast< Mapping
* >( &m_java2uno
);
204 &mapping
, Bridge_free
,
205 m_java_env
, &m_uno_env
->aBase
, nullptr );
209 uno_Mapping
* mapping
= const_cast< Mapping
* >( &m_uno2java
);
211 &mapping
, Bridge_free
,
212 &m_uno_env
->aBase
, m_java_env
, nullptr );
218 void Bridge::release() const
223 m_registered_java2uno
224 ? const_cast< Mapping
* >( &m_java2uno
)
225 : const_cast< Mapping
* >( &m_uno2java
) );
231 uno_Environment
* java_env
, uno_ExtEnvironment
* uno_env
,
232 bool registered_java2uno
)
234 m_uno_env( uno_env
),
235 m_java_env( java_env
),
236 m_registered_java2uno( registered_java2uno
)
238 assert(m_java_env
!= nullptr);
239 assert(m_uno_env
!= nullptr);
241 // uno_initEnvironment (below) cannot report errors directly, so it clears
242 // its pContext upon error to indirectly report errors from here:
243 if (static_cast<jni_uno::JniUnoEnvironmentData
*>(m_java_env
->pContext
)
246 throw BridgeRuntimeError("error during JNI-UNO's uno_initEnvironment");
249 (*m_uno_env
->aBase
.acquire
)( &m_uno_env
->aBase
);
250 (*m_java_env
->acquire
)( m_java_env
);
253 m_java2uno
.acquire
= Mapping_acquire
;
254 m_java2uno
.release
= Mapping_release
;
255 m_java2uno
.mapInterface
= Mapping_map_to_uno
;
256 m_java2uno
.m_bridge
= this;
258 m_uno2java
.acquire
= Mapping_acquire
;
259 m_uno2java
.release
= Mapping_release
;
260 m_uno2java
.mapInterface
= Mapping_map_to_java
;
261 m_uno2java
.m_bridge
= this;
267 (*m_java_env
->release
)( m_java_env
);
268 (*m_uno_env
->aBase
.release
)( &m_uno_env
->aBase
);
271 JNI_info
const * Bridge::getJniInfo() const {
272 return static_cast<jni_uno::JniUnoEnvironmentData
*>(m_java_env
->pContext
)
276 void JNI_context::java_exc_occurred() const
278 // !don't rely on JNI_info!
280 JLocalAutoRef
jo_exc( *this, m_env
->ExceptionOccurred() );
281 m_env
->ExceptionClear();
285 throw BridgeRuntimeError(
286 "java exception occurred, but not available!?" +
290 // call toString(); don't rely on m_jni_info
291 jclass jo_class
= m_env
->FindClass( "java/lang/Object" );
292 if (m_env
->ExceptionCheck())
294 m_env
->ExceptionClear();
295 throw BridgeRuntimeError(
296 "cannot get class java.lang.Object!" + get_stack_trace() );
298 JLocalAutoRef
jo_Object( *this, jo_class
);
299 // method Object.toString()
300 jmethodID method_Object_toString
= m_env
->GetMethodID(
301 static_cast<jclass
>(jo_Object
.get()), "toString", "()Ljava/lang/String;" );
302 if (m_env
->ExceptionCheck())
304 m_env
->ExceptionClear();
305 throw BridgeRuntimeError(
306 "cannot get method id of java.lang.Object.toString()!" +
309 assert(method_Object_toString
!= nullptr);
311 JLocalAutoRef
jo_descr(
312 *this, m_env
->CallObjectMethodA(
313 jo_exc
.get(), method_Object_toString
, nullptr ) );
314 if (m_env
->ExceptionCheck()) // no chance at all
316 m_env
->ExceptionClear();
317 throw BridgeRuntimeError(
318 "error examining java exception object!" +
322 jsize len
= m_env
->GetStringLength( static_cast<jstring
>(jo_descr
.get()) );
323 std::unique_ptr
< rtl_mem
> ustr_mem(
325 sizeof (rtl_uString
) + (len
* sizeof (sal_Unicode
)) ) );
326 rtl_uString
* ustr
= reinterpret_cast<rtl_uString
*>(ustr_mem
.get());
327 m_env
->GetStringRegion( static_cast<jstring
>(jo_descr
.get()), 0, len
, reinterpret_cast<jchar
*>(ustr
->buffer
) );
328 if (m_env
->ExceptionCheck())
330 m_env
->ExceptionClear();
331 throw BridgeRuntimeError(
332 "invalid java string object!" + get_stack_trace() );
336 ustr
->buffer
[ len
] = '\0';
337 OUString
message( reinterpret_cast<rtl_uString
*>(ustr_mem
.release()), SAL_NO_ACQUIRE
);
339 throw BridgeRuntimeError( message
+ get_stack_trace( jo_exc
.get() ) );
343 void JNI_context::getClassForName(
344 jclass
* classClass
, jmethodID
* methodForName
) const
346 jclass c
= m_env
->FindClass("java/lang/Class");
348 *methodForName
= m_env
->GetStaticMethodID(
350 "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
356 jclass
JNI_context::findClass(
357 char const * name
, jclass classClass
, jmethodID methodForName
,
358 bool inException
) const
361 JLocalAutoRef
s(*this, m_env
->NewStringUTF(name
));
366 a
[2].l
= m_class_loader
;
367 c
= static_cast< jclass
>(
368 m_env
->CallStaticObjectMethodA(classClass
, methodForName
, a
));
371 ensure_no_exception();
377 OUString
JNI_context::get_stack_trace( jobject jo_exc
) const
379 JLocalAutoRef
jo_JNI_proxy(
381 find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) );
382 if (assert_no_exception())
384 // static method JNI_proxy.get_stack_trace()
385 jmethodID method
= m_env
->GetStaticMethodID(
386 static_cast<jclass
>(jo_JNI_proxy
.get()), "get_stack_trace",
387 "(Ljava/lang/Throwable;)Ljava/lang/String;" );
388 if (assert_no_exception() && (method
!= nullptr))
392 JLocalAutoRef
jo_stack_trace(
393 *this, m_env
->CallStaticObjectMethodA(
394 static_cast<jclass
>(jo_JNI_proxy
.get()), method
, &arg
) );
395 if (assert_no_exception())
398 m_env
->GetStringLength( static_cast<jstring
>(jo_stack_trace
.get()) );
399 std::unique_ptr
< rtl_mem
> ustr_mem(
401 sizeof (rtl_uString
) + (len
* sizeof (sal_Unicode
)) ) );
402 rtl_uString
* ustr
= reinterpret_cast<rtl_uString
*>(ustr_mem
.get());
403 m_env
->GetStringRegion(
404 static_cast<jstring
>(jo_stack_trace
.get()), 0, len
, reinterpret_cast<jchar
*>(ustr
->buffer
) );
405 if (assert_no_exception())
409 ustr
->buffer
[ len
] = '\0';
411 reinterpret_cast<rtl_uString
*>(ustr_mem
.release()), SAL_NO_ACQUIRE
);
421 using namespace ::jni_uno
;
425 static void java_env_dispose(uno_Environment
* env
) {
427 = static_cast<jni_uno::JniUnoEnvironmentData
*>(env
->pContext
);
428 if (envData
!= nullptr) {
431 osl::MutexGuard
g(envData
->mutex
);
432 async
= envData
->asynchronousFinalizer
;
433 envData
->asynchronousFinalizer
= nullptr;
435 if (async
!= nullptr) {
437 JNI_guarded_context
jni(envData
->info
, envData
->machine
);
438 jni
->CallObjectMethodA(
439 async
, envData
->info
->m_method_AsynchronousFinalizer_drain
,
441 jni
.ensure_no_exception();
442 jni
->DeleteGlobalRef(async
);
443 } catch (const BridgeRuntimeError
& e
) {
446 "ignoring BridgeRuntimeError \"" << e
.m_message
<< "\"");
448 jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
452 ("ignoring jvmaccess::VirtualMachine::AttachGuard"
453 "::CreationException"));
459 static void java_env_disposing(uno_Environment
* env
) {
460 java_env_dispose(env
);
461 delete static_cast<jni_uno::JniUnoEnvironmentData
*>(env
->pContext
);
464 #ifdef DISABLE_DYNLOADING
465 #define uno_initEnvironment java_uno_initEnvironment
469 SAL_DLLPUBLIC_EXPORT
void uno_initEnvironment( uno_Environment
* java_env
)
473 // JavaComponentLoader::getJavaLoader (in
474 // stoc/source/javaloader/javaloader.cxx) stores a
475 // jvmaccess::UnoVirtualMachine pointer into java_env->pContext; replace
476 // it here with either a pointer to a full JniUnoEnvironmentData upon
477 // success, or with a null pointer upon failure (as this function cannot
478 // directly report back failure, so it uses that way to indirectly
479 // report failure later from within the Bridge ctor):
480 rtl::Reference
<jvmaccess::UnoVirtualMachine
> vm(
481 static_cast<jvmaccess::UnoVirtualMachine
*>(java_env
->pContext
));
482 java_env
->pContext
= nullptr;
483 java_env
->dispose
= java_env_dispose
;
484 java_env
->environmentDisposing
= java_env_disposing
;
485 java_env
->pExtEnv
= nullptr; // no extended support
486 std::unique_ptr
<jni_uno::JniUnoEnvironmentData
> envData(
487 new jni_uno::JniUnoEnvironmentData(vm
));
489 JNI_guarded_context
jni(envData
->info
, envData
->machine
);
493 envData
->info
->m_class_AsynchronousFinalizer
,
494 envData
->info
->m_ctor_AsynchronousFinalizer
));
495 jni
.ensure_no_exception();
496 envData
->asynchronousFinalizer
= jni
->NewGlobalRef(ref
.get());
497 jni
.ensure_no_exception();
499 java_env
->pContext
= envData
.release();
500 } catch (const BridgeRuntimeError
& e
) {
501 SAL_WARN("bridges", "BridgeRuntimeError \"" << e
.m_message
<< "\"");
502 } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException
&) {
505 "jvmaccess::VirtualMachine::AttachGuard::CreationException");
509 #ifdef DISABLE_DYNLOADING
510 #define uno_ext_getMapping java_uno_ext_getMapping
514 SAL_DLLPUBLIC_EXPORT
void uno_ext_getMapping(
515 uno_Mapping
** ppMapping
, uno_Environment
* pFrom
, uno_Environment
* pTo
)
518 assert(ppMapping
!= nullptr);
519 assert(pFrom
!= nullptr);
520 assert(pTo
!= nullptr);
521 if (*ppMapping
!= nullptr)
523 (*(*ppMapping
)->release
)( *ppMapping
);
524 *ppMapping
= nullptr;
527 static_assert(int(JNI_FALSE
) == int(false), "must be equal");
528 static_assert(int(JNI_TRUE
) == int(true), "must be equal");
529 static_assert(sizeof (jboolean
) == sizeof (sal_Bool
), "must be the same size");
530 static_assert(sizeof (jchar
) == sizeof (sal_Unicode
), "must be the same size");
531 static_assert(sizeof (jdouble
) == sizeof (double), "must be the same size");
532 static_assert(sizeof (jfloat
) == sizeof (float), "must be the same size");
533 static_assert(sizeof (jbyte
) == sizeof (sal_Int8
), "must be the same size");
534 static_assert(sizeof (jshort
) == sizeof (sal_Int16
), "must be the same size");
535 static_assert(sizeof (jint
) == sizeof (sal_Int32
), "must be the same size");
536 static_assert(sizeof (jlong
) == sizeof (sal_Int64
), "must be the same size");
538 OUString
const & from_env_typename
=
539 OUString::unacquired( &pFrom
->pTypeName
);
540 OUString
const & to_env_typename
=
541 OUString::unacquired( &pTo
->pTypeName
);
543 uno_Mapping
* mapping
= nullptr;
547 if ( from_env_typename
== UNO_LB_JAVA
&& to_env_typename
== UNO_LB_UNO
)
550 new Bridge( pFrom
, pTo
->pExtEnv
, true ); // ref count = 1
551 mapping
= &bridge
->m_java2uno
;
553 &mapping
, Bridge_free
,
554 pFrom
, &pTo
->pExtEnv
->aBase
, nullptr );
555 // coverity[leaked_storage] - on purpose
557 else if ( from_env_typename
== UNO_LB_UNO
&& to_env_typename
== UNO_LB_JAVA
)
560 new Bridge( pTo
, pFrom
->pExtEnv
, false ); // ref count = 1
561 mapping
= &bridge
->m_uno2java
;
563 &mapping
, Bridge_free
,
564 &pFrom
->pExtEnv
->aBase
, pTo
, nullptr );
565 // coverity[leaked_storage] - on purpose
568 catch (const BridgeRuntimeError
& err
)
570 SAL_WARN("bridges", "BridgeRuntimeError \"" << err
.m_message
<< "\"");
573 *ppMapping
= mapping
;
578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */