1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_bridges.hxx" 30 31 #include "jni_bridge.h" 32 33 #include "jvmaccess/unovirtualmachine.hxx" 34 #include "rtl/ref.hxx" 35 #include "rtl/unload.h" 36 #include "rtl/strbuf.hxx" 37 #include "uno/lbnames.h" 38 39 40 using namespace ::std; 41 using namespace ::rtl; 42 using namespace ::osl; 43 using namespace ::jni_uno; 44 45 namespace 46 { 47 extern "C" 48 { 49 50 //------------------------------------------------------------------------------ 51 void SAL_CALL Mapping_acquire( uno_Mapping * mapping ) 52 SAL_THROW_EXTERN_C() 53 { 54 Mapping const * that = static_cast< Mapping const * >( mapping ); 55 that->m_bridge->acquire(); 56 } 57 58 //------------------------------------------------------------------------------ 59 void SAL_CALL Mapping_release( uno_Mapping * mapping ) 60 SAL_THROW_EXTERN_C() 61 { 62 Mapping const * that = static_cast< Mapping const * >( mapping ); 63 that->m_bridge->release(); 64 } 65 66 //------------------------------------------------------------------------------ 67 void SAL_CALL Mapping_map_to_uno( 68 uno_Mapping * mapping, void ** ppOut, 69 void * pIn, typelib_InterfaceTypeDescription * td ) 70 SAL_THROW_EXTERN_C() 71 { 72 uno_Interface ** ppUnoI = (uno_Interface **)ppOut; 73 jobject javaI = (jobject) pIn; 74 75 OSL_ASSERT( sizeof (void *) == sizeof (jobject) ); 76 OSL_ENSURE( ppUnoI && td, "### null ptr!" ); 77 78 if (0 == javaI) 79 { 80 if (0 != *ppUnoI) 81 { 82 uno_Interface * p = *(uno_Interface **)ppUnoI; 83 (*p->release)( p ); 84 *ppUnoI = 0; 85 } 86 } 87 else 88 { 89 try 90 { 91 Bridge const * bridge = 92 static_cast< Mapping const * >( mapping )->m_bridge; 93 JNI_guarded_context jni( 94 bridge->m_jni_info, 95 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( 96 bridge->m_java_env->pContext ) ); 97 98 JNI_interface_type_info const * info = 99 static_cast< JNI_interface_type_info const * >( 100 bridge->m_jni_info->get_type_info( 101 jni, (typelib_TypeDescription *)td ) ); 102 uno_Interface * pUnoI = bridge->map_to_uno( jni, javaI, info ); 103 if (0 != *ppUnoI) 104 { 105 uno_Interface * p = *(uno_Interface **)ppUnoI; 106 (*p->release)( p ); 107 } 108 *ppUnoI = pUnoI; 109 } 110 catch (BridgeRuntimeError & err) 111 { 112 #if OSL_DEBUG_LEVEL > 0 113 OString cstr_msg( 114 OUStringToOString( 115 OUSTR("[jni_uno bridge error] ") + err.m_message, 116 RTL_TEXTENCODING_ASCII_US ) ); 117 OSL_ENSURE( 0, cstr_msg.getStr() ); 118 #else 119 (void) err; // unused 120 #endif 121 } 122 catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) 123 { 124 OSL_ENSURE( 125 0, 126 "[jni_uno bridge error] attaching current thread " 127 "to java failed!" ); 128 } 129 } 130 } 131 132 //------------------------------------------------------------------------------ 133 void SAL_CALL Mapping_map_to_java( 134 uno_Mapping * mapping, void ** ppOut, 135 void * pIn, typelib_InterfaceTypeDescription * td ) 136 SAL_THROW_EXTERN_C() 137 { 138 jobject * ppJavaI = (jobject *) ppOut; 139 uno_Interface * pUnoI = (uno_Interface *)pIn; 140 141 OSL_ASSERT( sizeof (void *) == sizeof (jobject) ); 142 OSL_ENSURE( ppJavaI && td, "### null ptr!" ); 143 144 try 145 { 146 if (0 == pUnoI) 147 { 148 if (0 != *ppJavaI) 149 { 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 ) ); 156 jni->DeleteGlobalRef( *ppJavaI ); 157 *ppJavaI = 0; 158 } 159 } 160 else 161 { 162 Bridge const * bridge = 163 static_cast< Mapping const * >( mapping )->m_bridge; 164 JNI_guarded_context jni( 165 bridge->m_jni_info, 166 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( 167 bridge->m_java_env->pContext ) ); 168 169 JNI_interface_type_info const * info = 170 static_cast< JNI_interface_type_info const * >( 171 bridge->m_jni_info->get_type_info( 172 jni, (typelib_TypeDescription *)td ) ); 173 jobject jlocal = bridge->map_to_java( jni, pUnoI, info ); 174 if (0 != *ppJavaI) 175 jni->DeleteGlobalRef( *ppJavaI ); 176 *ppJavaI = jni->NewGlobalRef( jlocal ); 177 jni->DeleteLocalRef( jlocal ); 178 } 179 } 180 catch (BridgeRuntimeError & err) 181 { 182 #if OSL_DEBUG_LEVEL > 0 183 OString cstr_msg( 184 OUStringToOString( 185 OUSTR("[jni_uno bridge error] ") + err.m_message, 186 RTL_TEXTENCODING_ASCII_US ) ); 187 OSL_ENSURE( 0, cstr_msg.getStr() ); 188 #else 189 (void) err; // unused 190 #endif 191 } 192 catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) 193 { 194 OSL_ENSURE( 195 0, 196 "[jni_uno bridge error] attaching current thread to java failed!" ); 197 } 198 } 199 200 //______________________________________________________________________________ 201 void SAL_CALL Bridge_free( uno_Mapping * mapping ) 202 SAL_THROW_EXTERN_C() 203 { 204 Mapping * that = static_cast< Mapping * >( mapping ); 205 delete that->m_bridge; 206 } 207 208 } 209 210 rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT; 211 212 } 213 214 namespace jni_uno 215 { 216 217 //______________________________________________________________________________ 218 void Bridge::acquire() const SAL_THROW( () ) 219 { 220 if (1 == osl_incrementInterlockedCount( &m_ref )) 221 { 222 if (m_registered_java2uno) 223 { 224 uno_Mapping * mapping = const_cast< Mapping * >( &m_java2uno ); 225 uno_registerMapping( 226 &mapping, Bridge_free, 227 m_java_env, (uno_Environment *)m_uno_env, 0 ); 228 } 229 else 230 { 231 uno_Mapping * mapping = const_cast< Mapping * >( &m_uno2java ); 232 uno_registerMapping( 233 &mapping, Bridge_free, 234 (uno_Environment *)m_uno_env, m_java_env, 0 ); 235 } 236 } 237 } 238 239 //______________________________________________________________________________ 240 void Bridge::release() const SAL_THROW( () ) 241 { 242 if (! osl_decrementInterlockedCount( &m_ref )) 243 { 244 uno_revokeMapping( 245 m_registered_java2uno 246 ? const_cast< Mapping * >( &m_java2uno ) 247 : const_cast< Mapping * >( &m_uno2java ) ); 248 } 249 } 250 251 //______________________________________________________________________________ 252 Bridge::Bridge( 253 uno_Environment * java_env, uno_ExtEnvironment * uno_env, 254 bool registered_java2uno ) 255 : m_ref( 1 ), 256 m_uno_env( uno_env ), 257 m_java_env( java_env ), 258 m_registered_java2uno( registered_java2uno ) 259 { 260 // bootstrapping bridge jni_info 261 m_jni_info = JNI_info::get_jni_info( 262 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( 263 m_java_env->pContext ) ); 264 265 OSL_ASSERT( 0 != m_java_env && 0 != m_uno_env ); 266 (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env ); 267 (*m_java_env->acquire)( m_java_env ); 268 269 // java2uno 270 m_java2uno.acquire = Mapping_acquire; 271 m_java2uno.release = Mapping_release; 272 m_java2uno.mapInterface = Mapping_map_to_uno; 273 m_java2uno.m_bridge = this; 274 // uno2java 275 m_uno2java.acquire = Mapping_acquire; 276 m_uno2java.release = Mapping_release; 277 m_uno2java.mapInterface = Mapping_map_to_java; 278 m_uno2java.m_bridge = this; 279 280 (*g_moduleCount.modCnt.acquire)( &g_moduleCount.modCnt ); 281 } 282 283 //______________________________________________________________________________ 284 Bridge::~Bridge() SAL_THROW( () ) 285 { 286 (*m_java_env->release)( m_java_env ); 287 (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env ); 288 289 (*g_moduleCount.modCnt.release)( &g_moduleCount.modCnt ); 290 } 291 292 293 //______________________________________________________________________________ 294 void JNI_context::java_exc_occured() const 295 { 296 // !don't rely on JNI_info! 297 298 JLocalAutoRef jo_exc( *this, m_env->ExceptionOccurred() ); 299 m_env->ExceptionClear(); 300 OSL_ASSERT( jo_exc.is() ); 301 if (! jo_exc.is()) 302 { 303 throw BridgeRuntimeError( 304 OUSTR("java exception occured, but not available!?") + 305 get_stack_trace() ); 306 } 307 308 // call toString(); don't rely on m_jni_info 309 jclass jo_class = m_env->FindClass( "java/lang/Object" ); 310 if (JNI_FALSE != m_env->ExceptionCheck()) 311 { 312 m_env->ExceptionClear(); 313 throw BridgeRuntimeError( 314 OUSTR("cannot get class java.lang.Object!") + get_stack_trace() ); 315 } 316 JLocalAutoRef jo_Object( *this, jo_class ); 317 // method Object.toString() 318 jmethodID method_Object_toString = m_env->GetMethodID( 319 (jclass) jo_Object.get(), "toString", "()Ljava/lang/String;" ); 320 if (JNI_FALSE != m_env->ExceptionCheck()) 321 { 322 m_env->ExceptionClear(); 323 throw BridgeRuntimeError( 324 OUSTR("cannot get method id of java.lang.Object.toString()!") + 325 get_stack_trace() ); 326 } 327 OSL_ASSERT( 0 != method_Object_toString ); 328 329 JLocalAutoRef jo_descr( 330 *this, m_env->CallObjectMethodA( 331 jo_exc.get(), method_Object_toString, 0 ) ); 332 if (m_env->ExceptionCheck()) // no chance at all 333 { 334 m_env->ExceptionClear(); 335 throw BridgeRuntimeError( 336 OUSTR("error examining java exception object!") + 337 get_stack_trace() ); 338 } 339 340 jsize len = m_env->GetStringLength( (jstring) jo_descr.get() ); 341 auto_ptr< rtl_mem > ustr_mem( 342 rtl_mem::allocate( 343 sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) ); 344 rtl_uString * ustr = (rtl_uString *)ustr_mem.get(); 345 m_env->GetStringRegion( (jstring) jo_descr.get(), 0, len, ustr->buffer ); 346 if (m_env->ExceptionCheck()) 347 { 348 m_env->ExceptionClear(); 349 throw BridgeRuntimeError( 350 OUSTR("invalid java string object!") + get_stack_trace() ); 351 } 352 ustr->refCount = 1; 353 ustr->length = len; 354 ustr->buffer[ len ] = '\0'; 355 OUString message( (rtl_uString *)ustr_mem.release(), SAL_NO_ACQUIRE ); 356 357 throw BridgeRuntimeError( message + get_stack_trace( jo_exc.get() ) ); 358 } 359 360 //______________________________________________________________________________ 361 void JNI_context::getClassForName( 362 jclass * classClass, jmethodID * methodForName) const 363 { 364 jclass c = m_env->FindClass("java/lang/Class"); 365 if (c != 0) { 366 *methodForName = m_env->GetStaticMethodID( 367 c, "forName", 368 "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); 369 } 370 *classClass = c; 371 } 372 373 //______________________________________________________________________________ 374 jclass JNI_context::findClass( 375 char const * name, jclass classClass, jmethodID methodForName, 376 bool inException) const 377 { 378 jclass c = 0; 379 JLocalAutoRef s(*this, m_env->NewStringUTF(name)); 380 if (s.is()) { 381 jvalue a[3]; 382 a[0].l = s.get(); 383 a[1].z = JNI_FALSE; 384 a[2].l = m_class_loader; 385 c = static_cast< jclass >( 386 m_env->CallStaticObjectMethodA(classClass, methodForName, a)); 387 } 388 if (!inException) { 389 ensure_no_exception(); 390 } 391 return c; 392 } 393 394 //______________________________________________________________________________ 395 OUString JNI_context::get_stack_trace( jobject jo_exc ) const 396 { 397 JLocalAutoRef jo_JNI_proxy( 398 *this, 399 find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) ); 400 if (assert_no_exception()) 401 { 402 // static method JNI_proxy.get_stack_trace() 403 jmethodID method = m_env->GetStaticMethodID( 404 (jclass) jo_JNI_proxy.get(), "get_stack_trace", 405 "(Ljava/lang/Throwable;)Ljava/lang/String;" ); 406 if (assert_no_exception() && (0 != method)) 407 { 408 jvalue arg; 409 arg.l = jo_exc; 410 JLocalAutoRef jo_stack_trace( 411 *this, m_env->CallStaticObjectMethodA( 412 (jclass) jo_JNI_proxy.get(), method, &arg ) ); 413 if (assert_no_exception()) 414 { 415 jsize len = 416 m_env->GetStringLength( (jstring) jo_stack_trace.get() ); 417 auto_ptr< rtl_mem > ustr_mem( 418 rtl_mem::allocate( 419 sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) ); 420 rtl_uString * ustr = (rtl_uString *)ustr_mem.get(); 421 m_env->GetStringRegion( 422 (jstring) jo_stack_trace.get(), 0, len, ustr->buffer ); 423 if (assert_no_exception()) 424 { 425 ustr->refCount = 1; 426 ustr->length = len; 427 ustr->buffer[ len ] = '\0'; 428 return OUString( 429 (rtl_uString *)ustr_mem.release(), SAL_NO_ACQUIRE ); 430 } 431 } 432 } 433 } 434 return OUString(); 435 } 436 437 } 438 439 using namespace ::jni_uno; 440 441 extern "C" 442 { 443 namespace 444 { 445 446 //------------------------------------------------------------------------------ 447 void SAL_CALL java_env_disposing( uno_Environment * java_env ) 448 SAL_THROW_EXTERN_C() 449 { 450 ::jvmaccess::UnoVirtualMachine * machine = 451 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( 452 java_env->pContext ); 453 java_env->pContext = 0; 454 machine->release(); 455 } 456 } 457 458 //------------------------------------------------------------------------------ 459 void SAL_CALL uno_initEnvironment( uno_Environment * java_env ) 460 SAL_THROW_EXTERN_C() 461 { 462 java_env->environmentDisposing = java_env_disposing; 463 java_env->pExtEnv = 0; // no extended support 464 OSL_ASSERT( 0 != java_env->pContext ); 465 466 ::jvmaccess::UnoVirtualMachine * machine = 467 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( 468 java_env->pContext ); 469 machine->acquire(); 470 } 471 472 //------------------------------------------------------------------------------ 473 void SAL_CALL uno_ext_getMapping( 474 uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo ) 475 SAL_THROW_EXTERN_C() 476 { 477 OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo ); 478 if (0 != *ppMapping) 479 { 480 (*(*ppMapping)->release)( *ppMapping ); 481 *ppMapping = 0; 482 } 483 484 OSL_ASSERT( JNI_FALSE == sal_False ); 485 OSL_ASSERT( JNI_TRUE == sal_True ); 486 OSL_ASSERT( sizeof (jboolean) == sizeof (sal_Bool) ); 487 OSL_ASSERT( sizeof (jchar) == sizeof (sal_Unicode) ); 488 OSL_ASSERT( sizeof (jdouble) == sizeof (double) ); 489 OSL_ASSERT( sizeof (jfloat) == sizeof (float) ); 490 OSL_ASSERT( sizeof (jbyte) == sizeof (sal_Int8) ); 491 OSL_ASSERT( sizeof (jshort) == sizeof (sal_Int16) ); 492 OSL_ASSERT( sizeof (jint) == sizeof (sal_Int32) ); 493 OSL_ASSERT( sizeof (jlong) == sizeof (sal_Int64) ); 494 if ((JNI_FALSE == sal_False) && 495 (JNI_TRUE == sal_True) && 496 (sizeof (jboolean) == sizeof (sal_Bool)) && 497 (sizeof (jchar) == sizeof (sal_Unicode)) && 498 (sizeof (jdouble) == sizeof (double)) && 499 (sizeof (jfloat) == sizeof (float)) && 500 (sizeof (jbyte) == sizeof (sal_Int8)) && 501 (sizeof (jshort) == sizeof (sal_Int16)) && 502 (sizeof (jint) == sizeof (sal_Int32)) && 503 (sizeof (jlong) == sizeof (sal_Int64))) 504 { 505 OUString const & from_env_typename = 506 OUString::unacquired( &pFrom->pTypeName ); 507 OUString const & to_env_typename = 508 OUString::unacquired( &pTo->pTypeName ); 509 510 uno_Mapping * mapping = 0; 511 512 try 513 { 514 if (from_env_typename.equalsAsciiL( 515 RTL_CONSTASCII_STRINGPARAM(UNO_LB_JAVA) ) && 516 to_env_typename.equalsAsciiL( 517 RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) )) 518 { 519 Bridge * bridge = 520 new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1 521 mapping = &bridge->m_java2uno; 522 uno_registerMapping( 523 &mapping, Bridge_free, 524 pFrom, (uno_Environment *)pTo->pExtEnv, 0 ); 525 } 526 else if (from_env_typename.equalsAsciiL( 527 RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ) && 528 to_env_typename.equalsAsciiL( 529 RTL_CONSTASCII_STRINGPARAM(UNO_LB_JAVA) )) 530 { 531 Bridge * bridge = 532 new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1 533 mapping = &bridge->m_uno2java; 534 uno_registerMapping( 535 &mapping, Bridge_free, 536 (uno_Environment *)pFrom->pExtEnv, pTo, 0 ); 537 } 538 } 539 catch (BridgeRuntimeError & err) 540 { 541 #if OSL_DEBUG_LEVEL > 0 542 OString cstr_msg( 543 OUStringToOString( 544 OUSTR("[jni_uno bridge error] ") + err.m_message, 545 RTL_TEXTENCODING_ASCII_US ) ); 546 OSL_ENSURE( 0, cstr_msg.getStr() ); 547 #else 548 (void) err; // unused 549 #endif 550 } 551 catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) 552 { 553 OSL_ENSURE( 554 0, 555 "[jni_uno bridge error] attaching current thread " 556 "to java failed!" ); 557 } 558 559 *ppMapping = mapping; 560 } 561 } 562 563 //------------------------------------------------------------------------------ 564 sal_Bool SAL_CALL component_canUnload( TimeValue * pTime ) 565 SAL_THROW_EXTERN_C() 566 { 567 return (*g_moduleCount.canUnload)( &g_moduleCount, pTime ); 568 } 569 } 570