| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_bridges.hxx" |
| |
| #include "jni_bridge.h" |
| |
| #include "jvmaccess/unovirtualmachine.hxx" |
| #include "rtl/ref.hxx" |
| #include "rtl/unload.h" |
| #include "rtl/strbuf.hxx" |
| #include "uno/lbnames.h" |
| |
| |
| using namespace ::std; |
| using namespace ::rtl; |
| using namespace ::osl; |
| using namespace ::jni_uno; |
| |
| namespace |
| { |
| extern "C" |
| { |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL Mapping_acquire( uno_Mapping * mapping ) |
| SAL_THROW_EXTERN_C() |
| { |
| Mapping const * that = static_cast< Mapping const * >( mapping ); |
| that->m_bridge->acquire(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL Mapping_release( uno_Mapping * mapping ) |
| SAL_THROW_EXTERN_C() |
| { |
| Mapping const * that = static_cast< Mapping const * >( mapping ); |
| that->m_bridge->release(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL Mapping_map_to_uno( |
| uno_Mapping * mapping, void ** ppOut, |
| void * pIn, typelib_InterfaceTypeDescription * td ) |
| SAL_THROW_EXTERN_C() |
| { |
| uno_Interface ** ppUnoI = (uno_Interface **)ppOut; |
| jobject javaI = (jobject) pIn; |
| |
| OSL_ASSERT( sizeof (void *) == sizeof (jobject) ); |
| OSL_ENSURE( ppUnoI && td, "### null ptr!" ); |
| |
| if (0 == javaI) |
| { |
| if (0 != *ppUnoI) |
| { |
| uno_Interface * p = *(uno_Interface **)ppUnoI; |
| (*p->release)( p ); |
| *ppUnoI = 0; |
| } |
| } |
| else |
| { |
| try |
| { |
| Bridge const * bridge = |
| static_cast< Mapping const * >( mapping )->m_bridge; |
| JNI_guarded_context jni( |
| bridge->m_jni_info, |
| reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( |
| bridge->m_java_env->pContext ) ); |
| |
| JNI_interface_type_info const * info = |
| static_cast< JNI_interface_type_info const * >( |
| bridge->m_jni_info->get_type_info( |
| jni, (typelib_TypeDescription *)td ) ); |
| uno_Interface * pUnoI = bridge->map_to_uno( jni, javaI, info ); |
| if (0 != *ppUnoI) |
| { |
| uno_Interface * p = *(uno_Interface **)ppUnoI; |
| (*p->release)( p ); |
| } |
| *ppUnoI = pUnoI; |
| } |
| catch (BridgeRuntimeError & err) |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| OString cstr_msg( |
| OUStringToOString( |
| OUSTR("[jni_uno bridge error] ") + err.m_message, |
| RTL_TEXTENCODING_ASCII_US ) ); |
| OSL_ENSURE( 0, cstr_msg.getStr() ); |
| #else |
| (void) err; // unused |
| #endif |
| } |
| catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) |
| { |
| OSL_ENSURE( |
| 0, |
| "[jni_uno bridge error] attaching current thread " |
| "to java failed!" ); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL Mapping_map_to_java( |
| uno_Mapping * mapping, void ** ppOut, |
| void * pIn, typelib_InterfaceTypeDescription * td ) |
| SAL_THROW_EXTERN_C() |
| { |
| jobject * ppJavaI = (jobject *) ppOut; |
| uno_Interface * pUnoI = (uno_Interface *)pIn; |
| |
| OSL_ASSERT( sizeof (void *) == sizeof (jobject) ); |
| OSL_ENSURE( ppJavaI && td, "### null ptr!" ); |
| |
| try |
| { |
| if (0 == pUnoI) |
| { |
| if (0 != *ppJavaI) |
| { |
| Bridge const * bridge = |
| static_cast< Mapping const * >( mapping )->m_bridge; |
| JNI_guarded_context jni( |
| bridge->m_jni_info, |
| reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( |
| bridge->m_java_env->pContext ) ); |
| jni->DeleteGlobalRef( *ppJavaI ); |
| *ppJavaI = 0; |
| } |
| } |
| else |
| { |
| Bridge const * bridge = |
| static_cast< Mapping const * >( mapping )->m_bridge; |
| JNI_guarded_context jni( |
| bridge->m_jni_info, |
| reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( |
| bridge->m_java_env->pContext ) ); |
| |
| JNI_interface_type_info const * info = |
| static_cast< JNI_interface_type_info const * >( |
| bridge->m_jni_info->get_type_info( |
| jni, (typelib_TypeDescription *)td ) ); |
| jobject jlocal = bridge->map_to_java( jni, pUnoI, info ); |
| if (0 != *ppJavaI) |
| jni->DeleteGlobalRef( *ppJavaI ); |
| *ppJavaI = jni->NewGlobalRef( jlocal ); |
| jni->DeleteLocalRef( jlocal ); |
| } |
| } |
| catch (BridgeRuntimeError & err) |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| OString cstr_msg( |
| OUStringToOString( |
| OUSTR("[jni_uno bridge error] ") + err.m_message, |
| RTL_TEXTENCODING_ASCII_US ) ); |
| OSL_ENSURE( 0, cstr_msg.getStr() ); |
| #else |
| (void) err; // unused |
| #endif |
| } |
| catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) |
| { |
| OSL_ENSURE( |
| 0, |
| "[jni_uno bridge error] attaching current thread to java failed!" ); |
| } |
| } |
| |
| //______________________________________________________________________________ |
| void SAL_CALL Bridge_free( uno_Mapping * mapping ) |
| SAL_THROW_EXTERN_C() |
| { |
| Mapping * that = static_cast< Mapping * >( mapping ); |
| delete that->m_bridge; |
| } |
| |
| } |
| |
| rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT; |
| |
| } |
| |
| namespace jni_uno |
| { |
| |
| //______________________________________________________________________________ |
| void Bridge::acquire() const SAL_THROW( () ) |
| { |
| if (1 == osl_incrementInterlockedCount( &m_ref )) |
| { |
| if (m_registered_java2uno) |
| { |
| uno_Mapping * mapping = const_cast< Mapping * >( &m_java2uno ); |
| uno_registerMapping( |
| &mapping, Bridge_free, |
| m_java_env, (uno_Environment *)m_uno_env, 0 ); |
| } |
| else |
| { |
| uno_Mapping * mapping = const_cast< Mapping * >( &m_uno2java ); |
| uno_registerMapping( |
| &mapping, Bridge_free, |
| (uno_Environment *)m_uno_env, m_java_env, 0 ); |
| } |
| } |
| } |
| |
| //______________________________________________________________________________ |
| void Bridge::release() const SAL_THROW( () ) |
| { |
| if (! osl_decrementInterlockedCount( &m_ref )) |
| { |
| uno_revokeMapping( |
| m_registered_java2uno |
| ? const_cast< Mapping * >( &m_java2uno ) |
| : const_cast< Mapping * >( &m_uno2java ) ); |
| } |
| } |
| |
| //______________________________________________________________________________ |
| Bridge::Bridge( |
| uno_Environment * java_env, uno_ExtEnvironment * uno_env, |
| bool registered_java2uno ) |
| : m_ref( 1 ), |
| m_uno_env( uno_env ), |
| m_java_env( java_env ), |
| m_registered_java2uno( registered_java2uno ) |
| { |
| // bootstrapping bridge jni_info |
| m_jni_info = JNI_info::get_jni_info( |
| reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( |
| m_java_env->pContext ) ); |
| |
| OSL_ASSERT( 0 != m_java_env && 0 != m_uno_env ); |
| (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env ); |
| (*m_java_env->acquire)( m_java_env ); |
| |
| // java2uno |
| m_java2uno.acquire = Mapping_acquire; |
| m_java2uno.release = Mapping_release; |
| m_java2uno.mapInterface = Mapping_map_to_uno; |
| m_java2uno.m_bridge = this; |
| // uno2java |
| m_uno2java.acquire = Mapping_acquire; |
| m_uno2java.release = Mapping_release; |
| m_uno2java.mapInterface = Mapping_map_to_java; |
| m_uno2java.m_bridge = this; |
| |
| (*g_moduleCount.modCnt.acquire)( &g_moduleCount.modCnt ); |
| } |
| |
| //______________________________________________________________________________ |
| Bridge::~Bridge() SAL_THROW( () ) |
| { |
| (*m_java_env->release)( m_java_env ); |
| (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env ); |
| |
| (*g_moduleCount.modCnt.release)( &g_moduleCount.modCnt ); |
| } |
| |
| |
| //______________________________________________________________________________ |
| void JNI_context::java_exc_occured() const |
| { |
| // !don't rely on JNI_info! |
| |
| JLocalAutoRef jo_exc( *this, m_env->ExceptionOccurred() ); |
| m_env->ExceptionClear(); |
| OSL_ASSERT( jo_exc.is() ); |
| if (! jo_exc.is()) |
| { |
| throw BridgeRuntimeError( |
| OUSTR("java exception occured, but not available!?") + |
| get_stack_trace() ); |
| } |
| |
| // call toString(); don't rely on m_jni_info |
| jclass jo_class = m_env->FindClass( "java/lang/Object" ); |
| if (JNI_FALSE != m_env->ExceptionCheck()) |
| { |
| m_env->ExceptionClear(); |
| throw BridgeRuntimeError( |
| OUSTR("cannot get class java.lang.Object!") + get_stack_trace() ); |
| } |
| JLocalAutoRef jo_Object( *this, jo_class ); |
| // method Object.toString() |
| jmethodID method_Object_toString = m_env->GetMethodID( |
| (jclass) jo_Object.get(), "toString", "()Ljava/lang/String;" ); |
| if (JNI_FALSE != m_env->ExceptionCheck()) |
| { |
| m_env->ExceptionClear(); |
| throw BridgeRuntimeError( |
| OUSTR("cannot get method id of java.lang.Object.toString()!") + |
| get_stack_trace() ); |
| } |
| OSL_ASSERT( 0 != method_Object_toString ); |
| |
| JLocalAutoRef jo_descr( |
| *this, m_env->CallObjectMethodA( |
| jo_exc.get(), method_Object_toString, 0 ) ); |
| if (m_env->ExceptionCheck()) // no chance at all |
| { |
| m_env->ExceptionClear(); |
| throw BridgeRuntimeError( |
| OUSTR("error examining java exception object!") + |
| get_stack_trace() ); |
| } |
| |
| jsize len = m_env->GetStringLength( (jstring) jo_descr.get() ); |
| auto_ptr< rtl_mem > ustr_mem( |
| rtl_mem::allocate( |
| sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) ); |
| rtl_uString * ustr = (rtl_uString *)ustr_mem.get(); |
| m_env->GetStringRegion( (jstring) jo_descr.get(), 0, len, ustr->buffer ); |
| if (m_env->ExceptionCheck()) |
| { |
| m_env->ExceptionClear(); |
| throw BridgeRuntimeError( |
| OUSTR("invalid java string object!") + get_stack_trace() ); |
| } |
| ustr->refCount = 1; |
| ustr->length = len; |
| ustr->buffer[ len ] = '\0'; |
| OUString message( (rtl_uString *)ustr_mem.release(), SAL_NO_ACQUIRE ); |
| |
| throw BridgeRuntimeError( message + get_stack_trace( jo_exc.get() ) ); |
| } |
| |
| //______________________________________________________________________________ |
| void JNI_context::getClassForName( |
| jclass * classClass, jmethodID * methodForName) const |
| { |
| jclass c = m_env->FindClass("java/lang/Class"); |
| if (c != 0) { |
| *methodForName = m_env->GetStaticMethodID( |
| c, "forName", |
| "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); |
| } |
| *classClass = c; |
| } |
| |
| //______________________________________________________________________________ |
| jclass JNI_context::findClass( |
| char const * name, jclass classClass, jmethodID methodForName, |
| bool inException) const |
| { |
| jclass c = 0; |
| JLocalAutoRef s(*this, m_env->NewStringUTF(name)); |
| if (s.is()) { |
| jvalue a[3]; |
| a[0].l = s.get(); |
| a[1].z = JNI_FALSE; |
| a[2].l = m_class_loader; |
| c = static_cast< jclass >( |
| m_env->CallStaticObjectMethodA(classClass, methodForName, a)); |
| } |
| if (!inException) { |
| ensure_no_exception(); |
| } |
| return c; |
| } |
| |
| //______________________________________________________________________________ |
| OUString JNI_context::get_stack_trace( jobject jo_exc ) const |
| { |
| JLocalAutoRef jo_JNI_proxy( |
| *this, |
| find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) ); |
| if (assert_no_exception()) |
| { |
| // static method JNI_proxy.get_stack_trace() |
| jmethodID method = m_env->GetStaticMethodID( |
| (jclass) jo_JNI_proxy.get(), "get_stack_trace", |
| "(Ljava/lang/Throwable;)Ljava/lang/String;" ); |
| if (assert_no_exception() && (0 != method)) |
| { |
| jvalue arg; |
| arg.l = jo_exc; |
| JLocalAutoRef jo_stack_trace( |
| *this, m_env->CallStaticObjectMethodA( |
| (jclass) jo_JNI_proxy.get(), method, &arg ) ); |
| if (assert_no_exception()) |
| { |
| jsize len = |
| m_env->GetStringLength( (jstring) jo_stack_trace.get() ); |
| auto_ptr< rtl_mem > ustr_mem( |
| rtl_mem::allocate( |
| sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) ); |
| rtl_uString * ustr = (rtl_uString *)ustr_mem.get(); |
| m_env->GetStringRegion( |
| (jstring) jo_stack_trace.get(), 0, len, ustr->buffer ); |
| if (assert_no_exception()) |
| { |
| ustr->refCount = 1; |
| ustr->length = len; |
| ustr->buffer[ len ] = '\0'; |
| return OUString( |
| (rtl_uString *)ustr_mem.release(), SAL_NO_ACQUIRE ); |
| } |
| } |
| } |
| } |
| return OUString(); |
| } |
| |
| } |
| |
| using namespace ::jni_uno; |
| |
| extern "C" |
| { |
| namespace |
| { |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL java_env_disposing( uno_Environment * java_env ) |
| SAL_THROW_EXTERN_C() |
| { |
| ::jvmaccess::UnoVirtualMachine * machine = |
| reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( |
| java_env->pContext ); |
| java_env->pContext = 0; |
| machine->release(); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL uno_initEnvironment( uno_Environment * java_env ) |
| SAL_THROW_EXTERN_C() |
| { |
| java_env->environmentDisposing = java_env_disposing; |
| java_env->pExtEnv = 0; // no extended support |
| OSL_ASSERT( 0 != java_env->pContext ); |
| |
| ::jvmaccess::UnoVirtualMachine * machine = |
| reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( |
| java_env->pContext ); |
| machine->acquire(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL uno_ext_getMapping( |
| uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo ) |
| SAL_THROW_EXTERN_C() |
| { |
| OSL_ASSERT( 0 != ppMapping && 0 != pFrom && 0 != pTo ); |
| if (0 != *ppMapping) |
| { |
| (*(*ppMapping)->release)( *ppMapping ); |
| *ppMapping = 0; |
| } |
| |
| OSL_ASSERT( JNI_FALSE == sal_False ); |
| OSL_ASSERT( JNI_TRUE == sal_True ); |
| OSL_ASSERT( sizeof (jboolean) == sizeof (sal_Bool) ); |
| OSL_ASSERT( sizeof (jchar) == sizeof (sal_Unicode) ); |
| OSL_ASSERT( sizeof (jdouble) == sizeof (double) ); |
| OSL_ASSERT( sizeof (jfloat) == sizeof (float) ); |
| OSL_ASSERT( sizeof (jbyte) == sizeof (sal_Int8) ); |
| OSL_ASSERT( sizeof (jshort) == sizeof (sal_Int16) ); |
| OSL_ASSERT( sizeof (jint) == sizeof (sal_Int32) ); |
| OSL_ASSERT( sizeof (jlong) == sizeof (sal_Int64) ); |
| if ((JNI_FALSE == sal_False) && |
| (JNI_TRUE == sal_True) && |
| (sizeof (jboolean) == sizeof (sal_Bool)) && |
| (sizeof (jchar) == sizeof (sal_Unicode)) && |
| (sizeof (jdouble) == sizeof (double)) && |
| (sizeof (jfloat) == sizeof (float)) && |
| (sizeof (jbyte) == sizeof (sal_Int8)) && |
| (sizeof (jshort) == sizeof (sal_Int16)) && |
| (sizeof (jint) == sizeof (sal_Int32)) && |
| (sizeof (jlong) == sizeof (sal_Int64))) |
| { |
| OUString const & from_env_typename = |
| OUString::unacquired( &pFrom->pTypeName ); |
| OUString const & to_env_typename = |
| OUString::unacquired( &pTo->pTypeName ); |
| |
| uno_Mapping * mapping = 0; |
| |
| try |
| { |
| if (from_env_typename.equalsAsciiL( |
| RTL_CONSTASCII_STRINGPARAM(UNO_LB_JAVA) ) && |
| to_env_typename.equalsAsciiL( |
| RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) )) |
| { |
| Bridge * bridge = |
| new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1 |
| mapping = &bridge->m_java2uno; |
| uno_registerMapping( |
| &mapping, Bridge_free, |
| pFrom, (uno_Environment *)pTo->pExtEnv, 0 ); |
| } |
| else if (from_env_typename.equalsAsciiL( |
| RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ) && |
| to_env_typename.equalsAsciiL( |
| RTL_CONSTASCII_STRINGPARAM(UNO_LB_JAVA) )) |
| { |
| Bridge * bridge = |
| new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1 |
| mapping = &bridge->m_uno2java; |
| uno_registerMapping( |
| &mapping, Bridge_free, |
| (uno_Environment *)pFrom->pExtEnv, pTo, 0 ); |
| } |
| } |
| catch (BridgeRuntimeError & err) |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| OString cstr_msg( |
| OUStringToOString( |
| OUSTR("[jni_uno bridge error] ") + err.m_message, |
| RTL_TEXTENCODING_ASCII_US ) ); |
| OSL_ENSURE( 0, cstr_msg.getStr() ); |
| #else |
| (void) err; // unused |
| #endif |
| } |
| catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) |
| { |
| OSL_ENSURE( |
| 0, |
| "[jni_uno bridge error] attaching current thread " |
| "to java failed!" ); |
| } |
| |
| *ppMapping = mapping; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Bool SAL_CALL component_canUnload( TimeValue * pTime ) |
| SAL_THROW_EXTERN_C() |
| { |
| return (*g_moduleCount.canUnload)( &g_moduleCount, pTime ); |
| } |
| } |