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>
25 #include "jni_bridge.h"
26 #include "jniunoenvironmentdata.hxx"
28 #include "jvmaccess/unovirtualmachine.hxx"
29 #include "rtl/ref.hxx"
30 #include "rtl/strbuf.hxx"
31 #include "uno/lbnames.h"
33 using namespace ::osl
;
34 using namespace ::jni_uno
;
42 void SAL_CALL
Mapping_acquire( uno_Mapping
* mapping
)
45 Mapping
const * that
= static_cast< Mapping
const * >( mapping
);
46 that
->m_bridge
->acquire();
50 void SAL_CALL
Mapping_release( uno_Mapping
* mapping
)
53 Mapping
const * that
= static_cast< Mapping
const * >( mapping
);
54 that
->m_bridge
->release();
58 void SAL_CALL
Mapping_map_to_uno(
59 uno_Mapping
* mapping
, void ** ppOut
,
60 void * pIn
, typelib_InterfaceTypeDescription
* td
)
63 uno_Interface
** ppUnoI
= reinterpret_cast<uno_Interface
**>(ppOut
);
64 jobject javaI
= static_cast<jobject
>(pIn
);
66 static_assert(sizeof (void *) == sizeof (jobject
), "must be the same size");
74 uno_Interface
* p
= *ppUnoI
;
83 Bridge
const * bridge
=
84 static_cast< Mapping
const * >( mapping
)->m_bridge
;
85 JNI_guarded_context
jni(
87 (static_cast<jni_uno::JniUnoEnvironmentData
*>(
88 bridge
->m_java_env
->pContext
)
91 JNI_interface_type_info
const * info
=
92 static_cast< JNI_interface_type_info
const * >(
93 bridge
->getJniInfo()->get_type_info(
95 uno_Interface
* pUnoI
= bridge
->map_to_uno( jni
, javaI
, info
);
98 uno_Interface
* p
= *ppUnoI
;
103 catch (const BridgeRuntimeError
& err
)
107 "ingoring BridgeRuntimeError \"" << err
.m_message
<< "\"");
109 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
111 SAL_WARN("bridges", "attaching current thread to java failed");
117 void SAL_CALL
Mapping_map_to_java(
118 uno_Mapping
* mapping
, void ** ppOut
,
119 void * pIn
, typelib_InterfaceTypeDescription
* td
)
122 jobject
* ppJavaI
= reinterpret_cast<jobject
*>(ppOut
);
123 uno_Interface
* pUnoI
= static_cast<uno_Interface
*>(pIn
);
125 static_assert(sizeof (void *) == sizeof (jobject
), "must be the same size");
126 assert(ppJavaI
!= 0);
135 Bridge
const * bridge
=
136 static_cast< Mapping
const * >( mapping
)->m_bridge
;
137 JNI_guarded_context
jni(
138 bridge
->getJniInfo(),
139 (static_cast<jni_uno::JniUnoEnvironmentData
*>(
140 bridge
->m_java_env
->pContext
)
142 jni
->DeleteGlobalRef( *ppJavaI
);
148 Bridge
const * bridge
=
149 static_cast< Mapping
const * >( mapping
)->m_bridge
;
150 JNI_guarded_context
jni(
151 bridge
->getJniInfo(),
152 (static_cast<jni_uno::JniUnoEnvironmentData
*>(
153 bridge
->m_java_env
->pContext
)
156 JNI_interface_type_info
const * info
=
157 static_cast< JNI_interface_type_info
const * >(
158 bridge
->getJniInfo()->get_type_info(
160 jobject jlocal
= bridge
->map_to_java( jni
, pUnoI
, info
);
162 jni
->DeleteGlobalRef( *ppJavaI
);
163 *ppJavaI
= jni
->NewGlobalRef( jlocal
);
164 jni
->DeleteLocalRef( jlocal
);
167 catch (const BridgeRuntimeError
& err
)
171 "ingoring BridgeRuntimeError \"" << err
.m_message
<< "\"");
173 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
175 SAL_WARN("bridges", "attaching current thread to java failed");
180 void SAL_CALL
Bridge_free( uno_Mapping
* mapping
)
183 Mapping
* that
= static_cast< Mapping
* >( mapping
);
184 delete that
->m_bridge
;
195 void Bridge::acquire() const
197 if (1 == osl_atomic_increment( &m_ref
))
199 if (m_registered_java2uno
)
201 uno_Mapping
* mapping
= const_cast< Mapping
* >( &m_java2uno
);
203 &mapping
, Bridge_free
,
204 m_java_env
, &m_uno_env
->aBase
, 0 );
208 uno_Mapping
* mapping
= const_cast< Mapping
* >( &m_uno2java
);
210 &mapping
, Bridge_free
,
211 &m_uno_env
->aBase
, m_java_env
, 0 );
217 void Bridge::release() const
219 if (! osl_atomic_decrement( &m_ref
))
222 m_registered_java2uno
223 ? const_cast< Mapping
* >( &m_java2uno
)
224 : const_cast< Mapping
* >( &m_uno2java
) );
230 uno_Environment
* java_env
, uno_ExtEnvironment
* uno_env
,
231 bool registered_java2uno
)
233 m_uno_env( uno_env
),
234 m_java_env( java_env
),
235 m_registered_java2uno( registered_java2uno
)
237 assert(m_java_env
!= 0);
238 assert(m_uno_env
!= 0);
240 // uno_initEnvironment (below) cannot report errors directly, so it clears
241 // its pContext upon error to indirectly report errors from here:
242 if (static_cast<jni_uno::JniUnoEnvironmentData
*>(m_java_env
->pContext
)
245 throw BridgeRuntimeError("error during JNI-UNO's uno_initEnvironment");
248 (*m_uno_env
->aBase
.acquire
)( &m_uno_env
->aBase
);
249 (*m_java_env
->acquire
)( m_java_env
);
252 m_java2uno
.acquire
= Mapping_acquire
;
253 m_java2uno
.release
= Mapping_release
;
254 m_java2uno
.mapInterface
= Mapping_map_to_uno
;
255 m_java2uno
.m_bridge
= this;
257 m_uno2java
.acquire
= Mapping_acquire
;
258 m_uno2java
.release
= Mapping_release
;
259 m_uno2java
.mapInterface
= Mapping_map_to_java
;
260 m_uno2java
.m_bridge
= this;
266 (*m_java_env
->release
)( m_java_env
);
267 (*m_uno_env
->aBase
.release
)( &m_uno_env
->aBase
);
270 JNI_info
const * Bridge::getJniInfo() const {
271 return static_cast<jni_uno::JniUnoEnvironmentData
*>(m_java_env
->pContext
)
275 void JNI_context::java_exc_occurred() const
277 // !don't rely on JNI_info!
279 JLocalAutoRef
jo_exc( *this, m_env
->ExceptionOccurred() );
280 m_env
->ExceptionClear();
284 throw BridgeRuntimeError(
285 "java exception occurred, but not available!?" +
289 // call toString(); don't rely on m_jni_info
290 jclass jo_class
= m_env
->FindClass( "java/lang/Object" );
291 if (m_env
->ExceptionCheck())
293 m_env
->ExceptionClear();
294 throw BridgeRuntimeError(
295 "cannot get class java.lang.Object!" + get_stack_trace() );
297 JLocalAutoRef
jo_Object( *this, jo_class
);
298 // method Object.toString()
299 jmethodID method_Object_toString
= m_env
->GetMethodID(
300 static_cast<jclass
>(jo_Object
.get()), "toString", "()Ljava/lang/String;" );
301 if (m_env
->ExceptionCheck())
303 m_env
->ExceptionClear();
304 throw BridgeRuntimeError(
305 "cannot get method id of java.lang.Object.toString()!" +
308 assert(method_Object_toString
!= 0);
310 JLocalAutoRef
jo_descr(
311 *this, m_env
->CallObjectMethodA(
312 jo_exc
.get(), method_Object_toString
, 0 ) );
313 if (m_env
->ExceptionCheck()) // no chance at all
315 m_env
->ExceptionClear();
316 throw BridgeRuntimeError(
317 "error examining java exception object!" +
321 jsize len
= m_env
->GetStringLength( static_cast<jstring
>(jo_descr
.get()) );
322 std::unique_ptr
< rtl_mem
> ustr_mem(
324 sizeof (rtl_uString
) + (len
* sizeof (sal_Unicode
)) ) );
325 rtl_uString
* ustr
= reinterpret_cast<rtl_uString
*>(ustr_mem
.get());
326 m_env
->GetStringRegion( static_cast<jstring
>(jo_descr
.get()), 0, len
, ustr
->buffer
);
327 if (m_env
->ExceptionCheck())
329 m_env
->ExceptionClear();
330 throw BridgeRuntimeError(
331 "invalid java string object!" + get_stack_trace() );
335 ustr
->buffer
[ len
] = '\0';
336 OUString
message( reinterpret_cast<rtl_uString
*>(ustr_mem
.release()), SAL_NO_ACQUIRE
);
338 throw BridgeRuntimeError( message
+ get_stack_trace( jo_exc
.get() ) );
342 void JNI_context::getClassForName(
343 jclass
* classClass
, jmethodID
* methodForName
) const
345 jclass c
= m_env
->FindClass("java/lang/Class");
347 *methodForName
= m_env
->GetStaticMethodID(
349 "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
355 jclass
JNI_context::findClass(
356 char const * name
, jclass classClass
, jmethodID methodForName
,
357 bool inException
) const
360 JLocalAutoRef
s(*this, m_env
->NewStringUTF(name
));
365 a
[2].l
= m_class_loader
;
366 c
= static_cast< jclass
>(
367 m_env
->CallStaticObjectMethodA(classClass
, methodForName
, a
));
370 ensure_no_exception();
376 OUString
JNI_context::get_stack_trace( jobject jo_exc
) const
378 JLocalAutoRef
jo_JNI_proxy(
380 find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) );
381 if (assert_no_exception())
383 // static method JNI_proxy.get_stack_trace()
384 jmethodID method
= m_env
->GetStaticMethodID(
385 static_cast<jclass
>(jo_JNI_proxy
.get()), "get_stack_trace",
386 "(Ljava/lang/Throwable;)Ljava/lang/String;" );
387 if (assert_no_exception() && (0 != method
))
391 JLocalAutoRef
jo_stack_trace(
392 *this, m_env
->CallStaticObjectMethodA(
393 static_cast<jclass
>(jo_JNI_proxy
.get()), method
, &arg
) );
394 if (assert_no_exception())
397 m_env
->GetStringLength( static_cast<jstring
>(jo_stack_trace
.get()) );
398 std::unique_ptr
< rtl_mem
> ustr_mem(
400 sizeof (rtl_uString
) + (len
* sizeof (sal_Unicode
)) ) );
401 rtl_uString
* ustr
= reinterpret_cast<rtl_uString
*>(ustr_mem
.get());
402 m_env
->GetStringRegion(
403 static_cast<jstring
>(jo_stack_trace
.get()), 0, len
, ustr
->buffer
);
404 if (assert_no_exception())
408 ustr
->buffer
[ len
] = '\0';
410 reinterpret_cast<rtl_uString
*>(ustr_mem
.release()), SAL_NO_ACQUIRE
);
420 using namespace ::jni_uno
;
424 void SAL_CALL
java_env_dispose(uno_Environment
* env
) {
426 = static_cast<jni_uno::JniUnoEnvironmentData
*>(env
->pContext
);
427 if (envData
!= nullptr) {
430 osl::MutexGuard
g(envData
->mutex
);
431 async
= envData
->asynchronousFinalizer
;
432 envData
->asynchronousFinalizer
= nullptr;
434 if (async
!= nullptr) {
436 JNI_guarded_context
jni(envData
->info
, envData
->machine
);
437 jni
->CallObjectMethodA(
438 async
, envData
->info
->m_method_AsynchronousFinalizer_drain
,
440 jni
.ensure_no_exception();
441 jni
->DeleteGlobalRef(async
);
442 } catch (const BridgeRuntimeError
& e
) {
445 "ignoring BridgeRuntimeError \"" << e
.m_message
<< "\"");
447 jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
451 ("ignoring jvmaccess::VirtualMachine::AttachGuard"
452 "::CreationException"));
458 void SAL_CALL
java_env_disposing(uno_Environment
* env
) {
459 java_env_dispose(env
);
460 delete static_cast<jni_uno::JniUnoEnvironmentData
*>(env
->pContext
);
463 #ifdef DISABLE_DYNLOADING
464 #define uno_initEnvironment java_uno_initEnvironment
468 SAL_DLLPUBLIC_EXPORT
void SAL_CALL
uno_initEnvironment( uno_Environment
* java_env
)
472 // JavaComponentLoader::getJavaLoader (in
473 // stoc/source/javaloader/javaloader.cxx) stores a
474 // jvmaccess::UnoVirtualMachine pointer into java_env->pContext; replace
475 // it here with either a pointer to a full JniUnoEnvironmentData upon
476 // success, or with a null pointer upon failure (as this function cannot
477 // directly report back failure, so it uses that way to indirectly
478 // report failure later from within the Bridge ctor):
479 rtl::Reference
<jvmaccess::UnoVirtualMachine
> vm(
480 static_cast<jvmaccess::UnoVirtualMachine
*>(java_env
->pContext
));
481 java_env
->pContext
= nullptr;
482 java_env
->dispose
= java_env_dispose
;
483 java_env
->environmentDisposing
= java_env_disposing
;
484 java_env
->pExtEnv
= 0; // no extended support
485 std::unique_ptr
<jni_uno::JniUnoEnvironmentData
> envData(
486 new jni_uno::JniUnoEnvironmentData(vm
));
488 JNI_guarded_context
jni(envData
->info
, envData
->machine
);
492 envData
->info
->m_class_AsynchronousFinalizer
,
493 envData
->info
->m_ctor_AsynchronousFinalizer
));
494 jni
.ensure_no_exception();
495 envData
->asynchronousFinalizer
= jni
->NewGlobalRef(ref
.get());
496 jni
.ensure_no_exception();
498 java_env
->pContext
= envData
.release();
499 } catch (const BridgeRuntimeError
& e
) {
500 SAL_WARN("bridges", "BridgeRuntimeError \"" << e
.m_message
<< "\"");
501 } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException
&) {
504 "jvmaccess::VirtualMachine::AttachGuard::CreationException");
508 #ifdef DISABLE_DYNLOADING
509 #define uno_ext_getMapping java_uno_ext_getMapping
513 SAL_DLLPUBLIC_EXPORT
void SAL_CALL
uno_ext_getMapping(
514 uno_Mapping
** ppMapping
, uno_Environment
* pFrom
, uno_Environment
* pTo
)
517 assert(ppMapping
!= 0);
522 (*(*ppMapping
)->release
)( *ppMapping
);
526 static_assert(int(JNI_FALSE
) == int(sal_False
), "must be equal");
527 static_assert(int(JNI_TRUE
) == int(sal_True
), "must be equal");
528 static_assert(sizeof (jboolean
) == sizeof (sal_Bool
), "must be the same size");
529 static_assert(sizeof (jchar
) == sizeof (sal_Unicode
), "must be the same size");
530 static_assert(sizeof (jdouble
) == sizeof (double), "must be the same size");
531 static_assert(sizeof (jfloat
) == sizeof (float), "must be the same size");
532 static_assert(sizeof (jbyte
) == sizeof (sal_Int8
), "must be the same size");
533 static_assert(sizeof (jshort
) == sizeof (sal_Int16
), "must be the same size");
534 static_assert(sizeof (jint
) == sizeof (sal_Int32
), "must be the same size");
535 static_assert(sizeof (jlong
) == sizeof (sal_Int64
), "must be the same size");
537 OUString
const & from_env_typename
=
538 OUString::unacquired( &pFrom
->pTypeName
);
539 OUString
const & to_env_typename
=
540 OUString::unacquired( &pTo
->pTypeName
);
542 uno_Mapping
* mapping
= 0;
546 if ( from_env_typename
== UNO_LB_JAVA
&& to_env_typename
== UNO_LB_UNO
)
549 new Bridge( pFrom
, pTo
->pExtEnv
, true ); // ref count = 1
550 mapping
= &bridge
->m_java2uno
;
552 &mapping
, Bridge_free
,
553 pFrom
, &pTo
->pExtEnv
->aBase
, 0 );
554 // coverity[leaked_storage]
556 else if ( from_env_typename
== UNO_LB_UNO
&& to_env_typename
== UNO_LB_JAVA
)
559 new Bridge( pTo
, pFrom
->pExtEnv
, false ); // ref count = 1
560 mapping
= &bridge
->m_uno2java
;
562 &mapping
, Bridge_free
,
563 &pFrom
->pExtEnv
->aBase
, pTo
, 0 );
564 // coverity[leaked_storage]
567 catch (const BridgeRuntimeError
& err
)
569 SAL_WARN("bridges", "BridgeRuntimeError \"" << err
.m_message
<< "\"");
572 *ppMapping
= mapping
;
577 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */