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 .
21 #include "jni_bridge.h"
23 #include "jvmaccess/unovirtualmachine.hxx"
24 #include "rtl/ref.hxx"
25 #include "rtl/strbuf.hxx"
26 #include "uno/lbnames.h"
29 using namespace ::std
;
30 using namespace ::rtl
;
31 using namespace ::osl
;
32 using namespace ::jni_uno
;
39 //------------------------------------------------------------------------------
40 void SAL_CALL
Mapping_acquire( uno_Mapping
* mapping
)
43 Mapping
const * that
= static_cast< Mapping
const * >( mapping
);
44 that
->m_bridge
->acquire();
47 //------------------------------------------------------------------------------
48 void SAL_CALL
Mapping_release( uno_Mapping
* mapping
)
51 Mapping
const * that
= static_cast< Mapping
const * >( mapping
);
52 that
->m_bridge
->release();
55 //------------------------------------------------------------------------------
56 void SAL_CALL
Mapping_map_to_uno(
57 uno_Mapping
* mapping
, void ** ppOut
,
58 void * pIn
, typelib_InterfaceTypeDescription
* td
)
61 uno_Interface
** ppUnoI
= (uno_Interface
**)ppOut
;
62 jobject javaI
= (jobject
) pIn
;
64 OSL_ASSERT( sizeof (void *) == sizeof (jobject
) );
65 OSL_ENSURE( ppUnoI
&& td
, "### null ptr!" );
71 uno_Interface
* p
= *(uno_Interface
**)ppUnoI
;
80 Bridge
const * bridge
=
81 static_cast< Mapping
const * >( mapping
)->m_bridge
;
82 JNI_guarded_context
jni(
84 reinterpret_cast< ::jvmaccess::UnoVirtualMachine
* >(
85 bridge
->m_java_env
->pContext
) );
87 JNI_interface_type_info
const * info
=
88 static_cast< JNI_interface_type_info
const * >(
89 bridge
->m_jni_info
->get_type_info(
90 jni
, (typelib_TypeDescription
*)td
) );
91 uno_Interface
* pUnoI
= bridge
->map_to_uno( jni
, javaI
, info
);
94 uno_Interface
* p
= *(uno_Interface
**)ppUnoI
;
99 catch (const BridgeRuntimeError
& err
)
101 #if OSL_DEBUG_LEVEL > 0
104 "[jni_uno bridge error] " + err
.m_message
,
105 RTL_TEXTENCODING_ASCII_US
) );
106 OSL_FAIL( cstr_msg
.getStr() );
108 (void) err
; // unused
111 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
114 "[jni_uno bridge error] attaching current thread "
120 //------------------------------------------------------------------------------
121 void SAL_CALL
Mapping_map_to_java(
122 uno_Mapping
* mapping
, void ** ppOut
,
123 void * pIn
, typelib_InterfaceTypeDescription
* td
)
126 jobject
* ppJavaI
= (jobject
*) ppOut
;
127 uno_Interface
* pUnoI
= (uno_Interface
*)pIn
;
129 OSL_ASSERT( sizeof (void *) == sizeof (jobject
) );
130 OSL_ENSURE( ppJavaI
&& td
, "### null ptr!" );
138 Bridge
const * bridge
=
139 static_cast< Mapping
const * >( mapping
)->m_bridge
;
140 JNI_guarded_context
jni(
142 reinterpret_cast< ::jvmaccess::UnoVirtualMachine
* >(
143 bridge
->m_java_env
->pContext
) );
144 jni
->DeleteGlobalRef( *ppJavaI
);
150 Bridge
const * bridge
=
151 static_cast< Mapping
const * >( mapping
)->m_bridge
;
152 JNI_guarded_context
jni(
154 reinterpret_cast< ::jvmaccess::UnoVirtualMachine
* >(
155 bridge
->m_java_env
->pContext
) );
157 JNI_interface_type_info
const * info
=
158 static_cast< JNI_interface_type_info
const * >(
159 bridge
->m_jni_info
->get_type_info(
160 jni
, (typelib_TypeDescription
*)td
) );
161 jobject jlocal
= bridge
->map_to_java( jni
, pUnoI
, info
);
163 jni
->DeleteGlobalRef( *ppJavaI
);
164 *ppJavaI
= jni
->NewGlobalRef( jlocal
);
165 jni
->DeleteLocalRef( jlocal
);
168 catch (const BridgeRuntimeError
& err
)
170 #if OSL_DEBUG_LEVEL > 0
173 "[jni_uno bridge error] " + err
.m_message
,
174 RTL_TEXTENCODING_ASCII_US
) );
175 OSL_FAIL( cstr_msg
.getStr() );
177 (void) err
; // unused
180 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
183 "[jni_uno bridge error] attaching current thread to java failed!" );
187 //______________________________________________________________________________
188 void SAL_CALL
Bridge_free( uno_Mapping
* mapping
)
191 Mapping
* that
= static_cast< Mapping
* >( mapping
);
192 delete that
->m_bridge
;
202 //______________________________________________________________________________
203 void Bridge::acquire() const SAL_THROW(())
205 if (1 == osl_atomic_increment( &m_ref
))
207 if (m_registered_java2uno
)
209 uno_Mapping
* mapping
= const_cast< Mapping
* >( &m_java2uno
);
211 &mapping
, Bridge_free
,
212 m_java_env
, (uno_Environment
*)m_uno_env
, 0 );
216 uno_Mapping
* mapping
= const_cast< Mapping
* >( &m_uno2java
);
218 &mapping
, Bridge_free
,
219 (uno_Environment
*)m_uno_env
, m_java_env
, 0 );
224 //______________________________________________________________________________
225 void Bridge::release() const SAL_THROW(())
227 if (! osl_atomic_decrement( &m_ref
))
230 m_registered_java2uno
231 ? const_cast< Mapping
* >( &m_java2uno
)
232 : const_cast< Mapping
* >( &m_uno2java
) );
236 //______________________________________________________________________________
238 uno_Environment
* java_env
, uno_ExtEnvironment
* uno_env
,
239 bool registered_java2uno
)
241 m_uno_env( uno_env
),
242 m_java_env( java_env
),
243 m_registered_java2uno( registered_java2uno
)
245 // bootstrapping bridge jni_info
246 m_jni_info
= JNI_info::get_jni_info(
247 reinterpret_cast< ::jvmaccess::UnoVirtualMachine
* >(
248 m_java_env
->pContext
) );
250 OSL_ASSERT( 0 != m_java_env
&& 0 != m_uno_env
);
251 (*((uno_Environment
*)m_uno_env
)->acquire
)( (uno_Environment
*)m_uno_env
);
252 (*m_java_env
->acquire
)( m_java_env
);
255 m_java2uno
.acquire
= Mapping_acquire
;
256 m_java2uno
.release
= Mapping_release
;
257 m_java2uno
.mapInterface
= Mapping_map_to_uno
;
258 m_java2uno
.m_bridge
= this;
260 m_uno2java
.acquire
= Mapping_acquire
;
261 m_uno2java
.release
= Mapping_release
;
262 m_uno2java
.mapInterface
= Mapping_map_to_java
;
263 m_uno2java
.m_bridge
= this;
266 //______________________________________________________________________________
267 Bridge::~Bridge() SAL_THROW(())
269 (*m_java_env
->release
)( m_java_env
);
270 (*((uno_Environment
*)m_uno_env
)->release
)( (uno_Environment
*)m_uno_env
);
274 //______________________________________________________________________________
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();
281 OSL_ASSERT( jo_exc
.is() );
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 (JNI_FALSE
!= 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 (jclass
) jo_Object
.get(), "toString", "()Ljava/lang/String;" );
301 if (JNI_FALSE
!= m_env
->ExceptionCheck())
303 m_env
->ExceptionClear();
304 throw BridgeRuntimeError(
305 "cannot get method id of java.lang.Object.toString()!" +
308 OSL_ASSERT( 0 != method_Object_toString
);
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( (jstring
) jo_descr
.get() );
322 SAL_WNODEPRECATED_DECLARATIONS_PUSH
323 auto_ptr
< rtl_mem
> ustr_mem(
325 sizeof (rtl_uString
) + (len
* sizeof (sal_Unicode
)) ) );
326 SAL_WNODEPRECATED_DECLARATIONS_POP
327 rtl_uString
* ustr
= (rtl_uString
*)ustr_mem
.get();
328 m_env
->GetStringRegion( (jstring
) jo_descr
.get(), 0, len
, ustr
->buffer
);
329 if (m_env
->ExceptionCheck())
331 m_env
->ExceptionClear();
332 throw BridgeRuntimeError(
333 "invalid java string object!" + get_stack_trace() );
337 ustr
->buffer
[ len
] = '\0';
338 OUString
message( (rtl_uString
*)ustr_mem
.release(), SAL_NO_ACQUIRE
);
340 throw BridgeRuntimeError( message
+ get_stack_trace( jo_exc
.get() ) );
343 //______________________________________________________________________________
344 void JNI_context::getClassForName(
345 jclass
* classClass
, jmethodID
* methodForName
) const
347 jclass c
= m_env
->FindClass("java/lang/Class");
349 *methodForName
= m_env
->GetStaticMethodID(
351 "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
356 //______________________________________________________________________________
357 jclass
JNI_context::findClass(
358 char const * name
, jclass classClass
, jmethodID methodForName
,
359 bool inException
) const
362 JLocalAutoRef
s(*this, m_env
->NewStringUTF(name
));
367 a
[2].l
= m_class_loader
;
368 c
= static_cast< jclass
>(
369 m_env
->CallStaticObjectMethodA(classClass
, methodForName
, a
));
372 ensure_no_exception();
377 //______________________________________________________________________________
378 OUString
JNI_context::get_stack_trace( jobject jo_exc
) const
380 JLocalAutoRef
jo_JNI_proxy(
382 find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) );
383 if (assert_no_exception())
385 // static method JNI_proxy.get_stack_trace()
386 jmethodID method
= m_env
->GetStaticMethodID(
387 (jclass
) jo_JNI_proxy
.get(), "get_stack_trace",
388 "(Ljava/lang/Throwable;)Ljava/lang/String;" );
389 if (assert_no_exception() && (0 != method
))
393 JLocalAutoRef
jo_stack_trace(
394 *this, m_env
->CallStaticObjectMethodA(
395 (jclass
) jo_JNI_proxy
.get(), method
, &arg
) );
396 if (assert_no_exception())
399 m_env
->GetStringLength( (jstring
) jo_stack_trace
.get() );
400 SAL_WNODEPRECATED_DECLARATIONS_PUSH
401 auto_ptr
< rtl_mem
> ustr_mem(
403 sizeof (rtl_uString
) + (len
* sizeof (sal_Unicode
)) ) );
404 SAL_WNODEPRECATED_DECLARATIONS_POP
405 rtl_uString
* ustr
= (rtl_uString
*)ustr_mem
.get();
406 m_env
->GetStringRegion(
407 (jstring
) jo_stack_trace
.get(), 0, len
, ustr
->buffer
);
408 if (assert_no_exception())
412 ustr
->buffer
[ len
] = '\0';
414 (rtl_uString
*)ustr_mem
.release(), SAL_NO_ACQUIRE
);
424 using namespace ::jni_uno
;
431 //------------------------------------------------------------------------------
432 void SAL_CALL
java_env_disposing( uno_Environment
* java_env
)
435 ::jvmaccess::UnoVirtualMachine
* machine
=
436 reinterpret_cast< ::jvmaccess::UnoVirtualMachine
* >(
437 java_env
->pContext
);
438 java_env
->pContext
= 0;
443 #ifdef DISABLE_DYNLOADING
444 #define uno_initEnvironment java_uno_initEnvironment
447 //------------------------------------------------------------------------------
448 SAL_DLLPUBLIC_EXPORT
void SAL_CALL
uno_initEnvironment( uno_Environment
* java_env
)
451 java_env
->environmentDisposing
= java_env_disposing
;
452 java_env
->pExtEnv
= 0; // no extended support
453 OSL_ASSERT( 0 != java_env
->pContext
);
455 ::jvmaccess::UnoVirtualMachine
* machine
=
456 reinterpret_cast< ::jvmaccess::UnoVirtualMachine
* >(
457 java_env
->pContext
);
461 #ifdef DISABLE_DYNLOADING
462 #define uno_ext_getMapping java_uno_ext_getMapping
465 //------------------------------------------------------------------------------
466 SAL_DLLPUBLIC_EXPORT
void SAL_CALL
uno_ext_getMapping(
467 uno_Mapping
** ppMapping
, uno_Environment
* pFrom
, uno_Environment
* pTo
)
470 OSL_ASSERT( 0 != ppMapping
&& 0 != pFrom
&& 0 != pTo
);
473 (*(*ppMapping
)->release
)( *ppMapping
);
477 OSL_ASSERT( JNI_FALSE
== sal_False
);
478 OSL_ASSERT( JNI_TRUE
== sal_True
);
479 OSL_ASSERT( sizeof (jboolean
) == sizeof (sal_Bool
) );
480 OSL_ASSERT( sizeof (jchar
) == sizeof (sal_Unicode
) );
481 OSL_ASSERT( sizeof (jdouble
) == sizeof (double) );
482 OSL_ASSERT( sizeof (jfloat
) == sizeof (float) );
483 OSL_ASSERT( sizeof (jbyte
) == sizeof (sal_Int8
) );
484 OSL_ASSERT( sizeof (jshort
) == sizeof (sal_Int16
) );
485 OSL_ASSERT( sizeof (jint
) == sizeof (sal_Int32
) );
486 OSL_ASSERT( sizeof (jlong
) == sizeof (sal_Int64
) );
487 if ((JNI_FALSE
== sal_False
) &&
488 (JNI_TRUE
== sal_True
) &&
489 (sizeof (jboolean
) == sizeof (sal_Bool
)) &&
490 (sizeof (jchar
) == sizeof (sal_Unicode
)) &&
491 (sizeof (jdouble
) == sizeof (double)) &&
492 (sizeof (jfloat
) == sizeof (float)) &&
493 (sizeof (jbyte
) == sizeof (sal_Int8
)) &&
494 (sizeof (jshort
) == sizeof (sal_Int16
)) &&
495 (sizeof (jint
) == sizeof (sal_Int32
)) &&
496 (sizeof (jlong
) == sizeof (sal_Int64
)))
498 OUString
const & from_env_typename
=
499 OUString::unacquired( &pFrom
->pTypeName
);
500 OUString
const & to_env_typename
=
501 OUString::unacquired( &pTo
->pTypeName
);
503 uno_Mapping
* mapping
= 0;
507 if ( from_env_typename
== UNO_LB_JAVA
&& to_env_typename
== UNO_LB_UNO
)
510 new Bridge( pFrom
, pTo
->pExtEnv
, true ); // ref count = 1
511 mapping
= &bridge
->m_java2uno
;
513 &mapping
, Bridge_free
,
514 pFrom
, (uno_Environment
*)pTo
->pExtEnv
, 0 );
516 else if ( from_env_typename
== UNO_LB_UNO
&& to_env_typename
== UNO_LB_JAVA
)
519 new Bridge( pTo
, pFrom
->pExtEnv
, false ); // ref count = 1
520 mapping
= &bridge
->m_uno2java
;
522 &mapping
, Bridge_free
,
523 (uno_Environment
*)pFrom
->pExtEnv
, pTo
, 0 );
526 catch (const BridgeRuntimeError
& err
)
528 #if OSL_DEBUG_LEVEL > 0
531 "[jni_uno bridge error] " + err
.m_message
,
532 RTL_TEXTENCODING_ASCII_US
) );
533 OSL_FAIL( cstr_msg
.getStr() );
535 (void) err
; // unused
538 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
541 "[jni_uno bridge error] attaching current thread "
545 *ppMapping
= mapping
;
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */