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