50128fbab0
2008/03/28 16:30:42 rt 1.17.100.1: #i87441# Change license header to LPGL v3.
572 lines
19 KiB
C++
572 lines
19 KiB
C++
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2008 by Sun Microsystems, Inc.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: jni_bridge.cxx,v $
|
|
* $Revision: 1.18 $
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 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 );
|
|
}
|
|
}
|