Bump version to 4.1-6
[LibreOffice.git] / bridges / source / jni_uno / jni_bridge.cxx
blob8f77ad52393ab03d6ba8acc082ba26ac929c0316
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 .
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;
34 namespace
36 extern "C"
39 //------------------------------------------------------------------------------
40 void SAL_CALL Mapping_acquire( uno_Mapping * mapping )
41 SAL_THROW_EXTERN_C()
43 Mapping const * that = static_cast< Mapping const * >( mapping );
44 that->m_bridge->acquire();
47 //------------------------------------------------------------------------------
48 void SAL_CALL Mapping_release( uno_Mapping * mapping )
49 SAL_THROW_EXTERN_C()
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 )
59 SAL_THROW_EXTERN_C()
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!" );
67 if (0 == javaI)
69 if (0 != *ppUnoI)
71 uno_Interface * p = *(uno_Interface **)ppUnoI;
72 (*p->release)( p );
73 *ppUnoI = 0;
76 else
78 try
80 Bridge const * bridge =
81 static_cast< Mapping const * >( mapping )->m_bridge;
82 JNI_guarded_context jni(
83 bridge->m_jni_info,
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 );
92 if (0 != *ppUnoI)
94 uno_Interface * p = *(uno_Interface **)ppUnoI;
95 (*p->release)( p );
97 *ppUnoI = pUnoI;
99 catch (const BridgeRuntimeError & err)
101 #if OSL_DEBUG_LEVEL > 0
102 OString cstr_msg(
103 OUStringToOString(
104 "[jni_uno bridge error] " + err.m_message,
105 RTL_TEXTENCODING_ASCII_US ) );
106 OSL_FAIL( cstr_msg.getStr() );
107 #else
108 (void) err; // unused
109 #endif
111 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
113 OSL_FAIL(
114 "[jni_uno bridge error] attaching current thread "
115 "to java failed!" );
120 //------------------------------------------------------------------------------
121 void SAL_CALL Mapping_map_to_java(
122 uno_Mapping * mapping, void ** ppOut,
123 void * pIn, typelib_InterfaceTypeDescription * td )
124 SAL_THROW_EXTERN_C()
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!" );
134 if (0 == pUnoI)
136 if (0 != *ppJavaI)
138 Bridge const * bridge =
139 static_cast< Mapping const * >( mapping )->m_bridge;
140 JNI_guarded_context jni(
141 bridge->m_jni_info,
142 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
143 bridge->m_java_env->pContext ) );
144 jni->DeleteGlobalRef( *ppJavaI );
145 *ppJavaI = 0;
148 else
150 Bridge const * bridge =
151 static_cast< Mapping const * >( mapping )->m_bridge;
152 JNI_guarded_context jni(
153 bridge->m_jni_info,
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 );
162 if (0 != *ppJavaI)
163 jni->DeleteGlobalRef( *ppJavaI );
164 *ppJavaI = jni->NewGlobalRef( jlocal );
165 jni->DeleteLocalRef( jlocal );
168 catch (const BridgeRuntimeError & err)
170 #if OSL_DEBUG_LEVEL > 0
171 OString cstr_msg(
172 OUStringToOString(
173 "[jni_uno bridge error] " + err.m_message,
174 RTL_TEXTENCODING_ASCII_US ) );
175 OSL_FAIL( cstr_msg.getStr() );
176 #else
177 (void) err; // unused
178 #endif
180 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
182 OSL_FAIL(
183 "[jni_uno bridge error] attaching current thread to java failed!" );
187 //______________________________________________________________________________
188 void SAL_CALL Bridge_free( uno_Mapping * mapping )
189 SAL_THROW_EXTERN_C()
191 Mapping * that = static_cast< Mapping * >( mapping );
192 delete that->m_bridge;
199 namespace jni_uno
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 );
210 uno_registerMapping(
211 &mapping, Bridge_free,
212 m_java_env, (uno_Environment *)m_uno_env, 0 );
214 else
216 uno_Mapping * mapping = const_cast< Mapping * >( &m_uno2java );
217 uno_registerMapping(
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 ))
229 uno_revokeMapping(
230 m_registered_java2uno
231 ? const_cast< Mapping * >( &m_java2uno )
232 : const_cast< Mapping * >( &m_uno2java ) );
236 //______________________________________________________________________________
237 Bridge::Bridge(
238 uno_Environment * java_env, uno_ExtEnvironment * uno_env,
239 bool registered_java2uno )
240 : m_ref( 1 ),
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 );
254 // java2uno
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;
259 // uno2java
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() );
282 if (! jo_exc.is())
284 throw BridgeRuntimeError(
285 "java exception occurred, but not available!?" +
286 get_stack_trace() );
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()!" +
306 get_stack_trace() );
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!" +
318 get_stack_trace() );
321 jsize len = m_env->GetStringLength( (jstring) jo_descr.get() );
322 SAL_WNODEPRECATED_DECLARATIONS_PUSH
323 auto_ptr< rtl_mem > ustr_mem(
324 rtl_mem::allocate(
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() );
335 ustr->refCount = 1;
336 ustr->length = len;
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");
348 if (c != 0) {
349 *methodForName = m_env->GetStaticMethodID(
350 c, "forName",
351 "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
353 *classClass = c;
356 //______________________________________________________________________________
357 jclass JNI_context::findClass(
358 char const * name, jclass classClass, jmethodID methodForName,
359 bool inException) const
361 jclass c = 0;
362 JLocalAutoRef s(*this, m_env->NewStringUTF(name));
363 if (s.is()) {
364 jvalue a[3];
365 a[0].l = s.get();
366 a[1].z = JNI_FALSE;
367 a[2].l = m_class_loader;
368 c = static_cast< jclass >(
369 m_env->CallStaticObjectMethodA(classClass, methodForName, a));
371 if (!inException) {
372 ensure_no_exception();
374 return c;
377 //______________________________________________________________________________
378 OUString JNI_context::get_stack_trace( jobject jo_exc ) const
380 JLocalAutoRef jo_JNI_proxy(
381 *this,
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))
391 jvalue arg;
392 arg.l = jo_exc;
393 JLocalAutoRef jo_stack_trace(
394 *this, m_env->CallStaticObjectMethodA(
395 (jclass) jo_JNI_proxy.get(), method, &arg ) );
396 if (assert_no_exception())
398 jsize len =
399 m_env->GetStringLength( (jstring) jo_stack_trace.get() );
400 SAL_WNODEPRECATED_DECLARATIONS_PUSH
401 auto_ptr< rtl_mem > ustr_mem(
402 rtl_mem::allocate(
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())
410 ustr->refCount = 1;
411 ustr->length = len;
412 ustr->buffer[ len ] = '\0';
413 return OUString(
414 (rtl_uString *)ustr_mem.release(), SAL_NO_ACQUIRE );
419 return OUString();
424 using namespace ::jni_uno;
426 extern "C"
428 namespace
431 //------------------------------------------------------------------------------
432 void SAL_CALL java_env_disposing( uno_Environment * java_env )
433 SAL_THROW_EXTERN_C()
435 ::jvmaccess::UnoVirtualMachine * machine =
436 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
437 java_env->pContext );
438 java_env->pContext = 0;
439 machine->release();
443 #ifdef DISABLE_DYNLOADING
444 #define uno_initEnvironment java_uno_initEnvironment
445 #endif
447 //------------------------------------------------------------------------------
448 SAL_DLLPUBLIC_EXPORT void SAL_CALL uno_initEnvironment( uno_Environment * java_env )
449 SAL_THROW_EXTERN_C()
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 );
458 machine->acquire();
461 #ifdef DISABLE_DYNLOADING
462 #define uno_ext_getMapping java_uno_ext_getMapping
463 #endif
465 //------------------------------------------------------------------------------
466 SAL_DLLPUBLIC_EXPORT void SAL_CALL uno_ext_getMapping(
467 uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
468 SAL_THROW_EXTERN_C()
470 OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo );
471 if (0 != *ppMapping)
473 (*(*ppMapping)->release)( *ppMapping );
474 *ppMapping = 0;
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 )
509 Bridge * bridge =
510 new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1
511 mapping = &bridge->m_java2uno;
512 uno_registerMapping(
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 )
518 Bridge * bridge =
519 new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1
520 mapping = &bridge->m_uno2java;
521 uno_registerMapping(
522 &mapping, Bridge_free,
523 (uno_Environment *)pFrom->pExtEnv, pTo, 0 );
526 catch (const BridgeRuntimeError & err)
528 #if OSL_DEBUG_LEVEL > 0
529 OString cstr_msg(
530 OUStringToOString(
531 "[jni_uno bridge error] " + err.m_message,
532 RTL_TEXTENCODING_ASCII_US ) );
533 OSL_FAIL( cstr_msg.getStr() );
534 #else
535 (void) err; // unused
536 #endif
538 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
540 OSL_FAIL(
541 "[jni_uno bridge error] attaching current thread "
542 "to java failed!" );
545 *ppMapping = mapping;
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */