LCOV - code coverage report
Current view: top level - bridges/source/jni_uno - jni_bridge.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 73 182 40.1 %
Date: 2014-11-03 Functions: 10 16 62.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include <sal/config.h>
      21             : 
      22             : #include <cassert>
      23             : #include <memory>
      24             : 
      25             : #include "jni_bridge.h"
      26             : 
      27             : #include <boost/static_assert.hpp>
      28             : #include "jvmaccess/unovirtualmachine.hxx"
      29             : #include "rtl/ref.hxx"
      30             : #include "rtl/strbuf.hxx"
      31             : #include "uno/lbnames.h"
      32             : 
      33             : using namespace ::osl;
      34             : using namespace ::jni_uno;
      35             : 
      36             : namespace
      37             : {
      38             : extern "C"
      39             : {
      40             : 
      41             : 
      42          12 : void SAL_CALL Mapping_acquire( uno_Mapping * mapping )
      43             :     SAL_THROW_EXTERN_C()
      44             : {
      45          12 :     Mapping const * that = static_cast< Mapping const * >( mapping );
      46          12 :     that->m_bridge->acquire();
      47          12 : }
      48             : 
      49             : 
      50          18 : void SAL_CALL Mapping_release( uno_Mapping * mapping )
      51             :     SAL_THROW_EXTERN_C()
      52             : {
      53          18 :     Mapping const * that = static_cast< Mapping const * >( mapping );
      54          18 :     that->m_bridge->release();
      55          18 : }
      56             : 
      57             : 
      58           6 : void SAL_CALL Mapping_map_to_uno(
      59             :     uno_Mapping * mapping, void ** ppOut,
      60             :     void * pIn, typelib_InterfaceTypeDescription * td )
      61             :     SAL_THROW_EXTERN_C()
      62             : {
      63           6 :     uno_Interface ** ppUnoI = (uno_Interface **)ppOut;
      64           6 :     jobject javaI = (jobject) pIn;
      65             : 
      66             :     BOOST_STATIC_ASSERT( sizeof (void *) == sizeof (jobject) );
      67             :     assert(ppUnoI != 0);
      68             :     assert(td != 0);
      69             : 
      70           6 :     if (0 == javaI)
      71             :     {
      72           0 :         if (0 != *ppUnoI)
      73             :         {
      74           0 :             uno_Interface * p = *(uno_Interface **)ppUnoI;
      75           0 :             (*p->release)( p );
      76           0 :             *ppUnoI = 0;
      77             :         }
      78             :     }
      79             :     else
      80             :     {
      81             :         try
      82             :         {
      83             :             Bridge const * bridge =
      84           6 :                 static_cast< Mapping const * >( mapping )->m_bridge;
      85             :             JNI_guarded_context jni(
      86             :                 bridge->m_jni_info,
      87             :                 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
      88           6 :                     bridge->m_java_env->pContext ) );
      89             : 
      90             :             JNI_interface_type_info const * info =
      91             :                 static_cast< JNI_interface_type_info const * >(
      92             :                     bridge->m_jni_info->get_type_info(
      93           6 :                         jni, (typelib_TypeDescription *)td ) );
      94           6 :             uno_Interface * pUnoI = bridge->map_to_uno( jni, javaI, info );
      95           6 :             if (0 != *ppUnoI)
      96             :             {
      97           0 :                 uno_Interface * p = *(uno_Interface **)ppUnoI;
      98           0 :                 (*p->release)( p );
      99             :             }
     100           6 :             *ppUnoI = pUnoI;
     101             :         }
     102           0 :         catch (const BridgeRuntimeError & err)
     103             :         {
     104             :             SAL_WARN(
     105             :                 "bridges",
     106             :                 "ingoring BridgeRuntimeError \"" << err.m_message << "\"");
     107             :         }
     108           0 :         catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
     109             :         {
     110             :             SAL_WARN("bridges", "attaching current thread to java failed");
     111             :         }
     112             :     }
     113           6 : }
     114             : 
     115             : 
     116           0 : void SAL_CALL Mapping_map_to_java(
     117             :     uno_Mapping * mapping, void ** ppOut,
     118             :     void * pIn, typelib_InterfaceTypeDescription * td )
     119             :     SAL_THROW_EXTERN_C()
     120             : {
     121           0 :     jobject * ppJavaI = (jobject *) ppOut;
     122           0 :     uno_Interface * pUnoI = (uno_Interface *)pIn;
     123             : 
     124             :     BOOST_STATIC_ASSERT( sizeof (void *) == sizeof (jobject) );
     125             :     assert(ppJavaI != 0);
     126             :     assert(td != 0);
     127             : 
     128             :     try
     129             :     {
     130           0 :         if (0 == pUnoI)
     131             :         {
     132           0 :             if (0 != *ppJavaI)
     133             :             {
     134             :                 Bridge const * bridge =
     135           0 :                     static_cast< Mapping const * >( mapping )->m_bridge;
     136             :                 JNI_guarded_context jni(
     137             :                     bridge->m_jni_info,
     138             :                     reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
     139           0 :                         bridge->m_java_env->pContext ) );
     140           0 :                 jni->DeleteGlobalRef( *ppJavaI );
     141           0 :                 *ppJavaI = 0;
     142             :             }
     143             :         }
     144             :         else
     145             :         {
     146             :             Bridge const * bridge =
     147           0 :                 static_cast< Mapping const * >( mapping )->m_bridge;
     148             :             JNI_guarded_context jni(
     149             :                 bridge->m_jni_info,
     150             :                 reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
     151           0 :                     bridge->m_java_env->pContext ) );
     152             : 
     153             :             JNI_interface_type_info const * info =
     154             :                 static_cast< JNI_interface_type_info const * >(
     155             :                     bridge->m_jni_info->get_type_info(
     156           0 :                         jni, (typelib_TypeDescription *)td ) );
     157           0 :             jobject jlocal = bridge->map_to_java( jni, pUnoI, info );
     158           0 :             if (0 != *ppJavaI)
     159           0 :                 jni->DeleteGlobalRef( *ppJavaI );
     160           0 :             *ppJavaI = jni->NewGlobalRef( jlocal );
     161           0 :             jni->DeleteLocalRef( jlocal );
     162             :         }
     163             :     }
     164           0 :     catch (const BridgeRuntimeError & err)
     165             :     {
     166             :         SAL_WARN(
     167             :             "bridges",
     168             :             "ingoring BridgeRuntimeError \"" << err.m_message << "\"");
     169             :     }
     170           0 :     catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
     171             :     {
     172             :         SAL_WARN("bridges", "attaching current thread to java failed");
     173             :     }
     174           0 : }
     175             : 
     176             : 
     177           0 : void SAL_CALL Bridge_free( uno_Mapping * mapping )
     178             :     SAL_THROW_EXTERN_C()
     179             : {
     180           0 :     Mapping * that = static_cast< Mapping * >( mapping );
     181           0 :     delete that->m_bridge;
     182           0 : }
     183             : 
     184             : }
     185             : 
     186             : }
     187             : 
     188             : namespace jni_uno
     189             : {
     190             : 
     191             : 
     192         126 : void Bridge::acquire() const
     193             : {
     194         126 :     if (1 == osl_atomic_increment( &m_ref ))
     195             :     {
     196           0 :         if (m_registered_java2uno)
     197             :         {
     198           0 :             uno_Mapping * mapping = const_cast< Mapping * >( &m_java2uno );
     199             :             uno_registerMapping(
     200             :                 &mapping, Bridge_free,
     201           0 :                 m_java_env, (uno_Environment *)m_uno_env, 0 );
     202             :         }
     203             :         else
     204             :         {
     205           0 :             uno_Mapping * mapping = const_cast< Mapping * >( &m_uno2java );
     206             :             uno_registerMapping(
     207             :                 &mapping, Bridge_free,
     208           0 :                 (uno_Environment *)m_uno_env, m_java_env, 0 );
     209             :         }
     210             :     }
     211         126 : }
     212             : 
     213             : 
     214          68 : void Bridge::release() const
     215             : {
     216          68 :     if (! osl_atomic_decrement( &m_ref ))
     217             :     {
     218             :         uno_revokeMapping(
     219             :             m_registered_java2uno
     220             :             ? const_cast< Mapping * >( &m_java2uno )
     221           0 :             : const_cast< Mapping * >( &m_uno2java ) );
     222             :     }
     223          68 : }
     224             : 
     225             : 
     226           6 : Bridge::Bridge(
     227             :     uno_Environment * java_env, uno_ExtEnvironment * uno_env,
     228             :     bool registered_java2uno )
     229             :     : m_ref( 1 ),
     230             :       m_uno_env( uno_env ),
     231             :       m_java_env( java_env ),
     232           6 :       m_registered_java2uno( registered_java2uno )
     233             : {
     234             :     // bootstrapping bridge jni_info
     235             :     m_jni_info = JNI_info::get_jni_info(
     236             :         reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
     237           6 :             m_java_env->pContext ) );
     238             : 
     239             :     assert(m_java_env != 0);
     240             :     assert(m_uno_env != 0);
     241           6 :     (*((uno_Environment *)m_uno_env)->acquire)( (uno_Environment *)m_uno_env );
     242           6 :     (*m_java_env->acquire)( m_java_env );
     243             : 
     244             :     // java2uno
     245           6 :     m_java2uno.acquire = Mapping_acquire;
     246           6 :     m_java2uno.release = Mapping_release;
     247           6 :     m_java2uno.mapInterface = Mapping_map_to_uno;
     248           6 :     m_java2uno.m_bridge = this;
     249             :     // uno2java
     250           6 :     m_uno2java.acquire = Mapping_acquire;
     251           6 :     m_uno2java.release = Mapping_release;
     252           6 :     m_uno2java.mapInterface = Mapping_map_to_java;
     253           6 :     m_uno2java.m_bridge = this;
     254           6 : }
     255             : 
     256             : 
     257           0 : Bridge::~Bridge()
     258             : {
     259           0 :     (*m_java_env->release)( m_java_env );
     260           0 :     (*((uno_Environment *)m_uno_env)->release)( (uno_Environment *)m_uno_env );
     261           0 : }
     262             : 
     263             : 
     264             : 
     265           0 : void JNI_context::java_exc_occurred() const
     266             : {
     267             :     // !don't rely on JNI_info!
     268             : 
     269           0 :     JLocalAutoRef jo_exc( *this, m_env->ExceptionOccurred() );
     270           0 :     m_env->ExceptionClear();
     271             :     assert(jo_exc.is());
     272           0 :     if (! jo_exc.is())
     273             :     {
     274             :         throw BridgeRuntimeError(
     275           0 :             "java exception occurred, but not available!?" +
     276           0 :             get_stack_trace() );
     277             :     }
     278             : 
     279             :     // call toString(); don't rely on m_jni_info
     280           0 :     jclass jo_class = m_env->FindClass( "java/lang/Object" );
     281           0 :     if (JNI_FALSE != m_env->ExceptionCheck())
     282             :     {
     283           0 :         m_env->ExceptionClear();
     284             :         throw BridgeRuntimeError(
     285           0 :             "cannot get class java.lang.Object!" + get_stack_trace() );
     286             :     }
     287           0 :     JLocalAutoRef jo_Object( *this, jo_class );
     288             :     // method Object.toString()
     289             :     jmethodID method_Object_toString = m_env->GetMethodID(
     290           0 :         (jclass) jo_Object.get(), "toString", "()Ljava/lang/String;" );
     291           0 :     if (JNI_FALSE != m_env->ExceptionCheck())
     292             :     {
     293           0 :         m_env->ExceptionClear();
     294             :         throw BridgeRuntimeError(
     295           0 :             "cannot get method id of java.lang.Object.toString()!" +
     296           0 :             get_stack_trace() );
     297             :     }
     298             :     assert(method_Object_toString != 0);
     299             : 
     300             :     JLocalAutoRef jo_descr(
     301             :         *this, m_env->CallObjectMethodA(
     302           0 :             jo_exc.get(), method_Object_toString, 0 ) );
     303           0 :     if (m_env->ExceptionCheck()) // no chance at all
     304             :     {
     305           0 :         m_env->ExceptionClear();
     306             :         throw BridgeRuntimeError(
     307           0 :             "error examining java exception object!" +
     308           0 :             get_stack_trace() );
     309             :     }
     310             : 
     311           0 :     jsize len = m_env->GetStringLength( (jstring) jo_descr.get() );
     312             :     std::unique_ptr< rtl_mem > ustr_mem(
     313             :         rtl_mem::allocate(
     314           0 :             sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
     315           0 :     rtl_uString * ustr = (rtl_uString *)ustr_mem.get();
     316           0 :     m_env->GetStringRegion( (jstring) jo_descr.get(), 0, len, ustr->buffer );
     317           0 :     if (m_env->ExceptionCheck())
     318             :     {
     319           0 :         m_env->ExceptionClear();
     320             :         throw BridgeRuntimeError(
     321           0 :             "invalid java string object!" + get_stack_trace() );
     322             :     }
     323           0 :     ustr->refCount = 1;
     324           0 :     ustr->length = len;
     325           0 :     ustr->buffer[ len ] = '\0';
     326           0 :     OUString message( (rtl_uString *)ustr_mem.release(), SAL_NO_ACQUIRE );
     327             : 
     328           0 :     throw BridgeRuntimeError( message + get_stack_trace( jo_exc.get() ) );
     329             : }
     330             : 
     331             : 
     332           6 : void JNI_context::getClassForName(
     333             :     jclass * classClass, jmethodID * methodForName) const
     334             : {
     335           6 :     jclass c = m_env->FindClass("java/lang/Class");
     336           6 :     if (c != 0) {
     337             :         *methodForName = m_env->GetStaticMethodID(
     338             :             c, "forName",
     339           6 :             "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
     340             :     }
     341           6 :     *classClass = c;
     342           6 : }
     343             : 
     344             : 
     345         208 : jclass JNI_context::findClass(
     346             :     char const * name, jclass classClass, jmethodID methodForName,
     347             :     bool inException) const
     348             : {
     349         208 :     jclass c = 0;
     350         208 :     JLocalAutoRef s(*this, m_env->NewStringUTF(name));
     351         208 :     if (s.is()) {
     352             :         jvalue a[3];
     353         208 :         a[0].l = s.get();
     354         208 :         a[1].z = JNI_FALSE;
     355         208 :         a[2].l = m_class_loader;
     356             :         c = static_cast< jclass >(
     357         208 :             m_env->CallStaticObjectMethodA(classClass, methodForName, a));
     358             :     }
     359         208 :     if (!inException) {
     360         208 :         ensure_no_exception();
     361             :     }
     362         208 :     return c;
     363             : }
     364             : 
     365             : 
     366           0 : OUString JNI_context::get_stack_trace( jobject jo_exc ) const
     367             : {
     368             :     JLocalAutoRef jo_JNI_proxy(
     369             :         *this,
     370           0 :         find_class( *this, "com.sun.star.bridges.jni_uno.JNI_proxy", true ) );
     371           0 :     if (assert_no_exception())
     372             :     {
     373             :         // static method JNI_proxy.get_stack_trace()
     374             :         jmethodID method = m_env->GetStaticMethodID(
     375           0 :             (jclass) jo_JNI_proxy.get(), "get_stack_trace",
     376           0 :             "(Ljava/lang/Throwable;)Ljava/lang/String;" );
     377           0 :         if (assert_no_exception() && (0 != method))
     378             :         {
     379             :             jvalue arg;
     380           0 :             arg.l = jo_exc;
     381             :             JLocalAutoRef jo_stack_trace(
     382             :                 *this, m_env->CallStaticObjectMethodA(
     383           0 :                     (jclass) jo_JNI_proxy.get(), method, &arg ) );
     384           0 :             if (assert_no_exception())
     385             :             {
     386             :                 jsize len =
     387           0 :                     m_env->GetStringLength( (jstring) jo_stack_trace.get() );
     388             :                 std::unique_ptr< rtl_mem > ustr_mem(
     389             :                     rtl_mem::allocate(
     390           0 :                         sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) );
     391           0 :                 rtl_uString * ustr = (rtl_uString *)ustr_mem.get();
     392             :                 m_env->GetStringRegion(
     393           0 :                     (jstring) jo_stack_trace.get(), 0, len, ustr->buffer );
     394           0 :                 if (assert_no_exception())
     395             :                 {
     396           0 :                     ustr->refCount = 1;
     397           0 :                     ustr->length = len;
     398           0 :                     ustr->buffer[ len ] = '\0';
     399             :                     return OUString(
     400           0 :                         (rtl_uString *)ustr_mem.release(), SAL_NO_ACQUIRE );
     401           0 :                 }
     402           0 :             }
     403             :         }
     404             :     }
     405           0 :     return OUString();
     406             : }
     407             : 
     408             : }
     409             : 
     410             : using namespace ::jni_uno;
     411             : 
     412             : extern "C"
     413             : {
     414             : namespace
     415             : {
     416             : 
     417             : 
     418           0 : void SAL_CALL java_env_disposing( uno_Environment * java_env )
     419             :     SAL_THROW_EXTERN_C()
     420             : {
     421             :     ::jvmaccess::UnoVirtualMachine * machine =
     422             :           reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
     423           0 :               java_env->pContext );
     424           0 :     java_env->pContext = 0;
     425           0 :     machine->release();
     426           0 : }
     427             : }
     428             : 
     429             : #ifdef DISABLE_DYNLOADING
     430             : #define uno_initEnvironment java_uno_initEnvironment
     431             : #endif
     432             : 
     433             : 
     434           6 : SAL_DLLPUBLIC_EXPORT void SAL_CALL uno_initEnvironment( uno_Environment * java_env )
     435             :     SAL_THROW_EXTERN_C()
     436             : {
     437           6 :     java_env->environmentDisposing = java_env_disposing;
     438           6 :     java_env->pExtEnv = 0; // no extended support
     439             :     assert(java_env->pContext != 0);
     440             : 
     441             :     ::jvmaccess::UnoVirtualMachine * machine =
     442             :           reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >(
     443           6 :               java_env->pContext );
     444           6 :     machine->acquire();
     445           6 : }
     446             : 
     447             : #ifdef DISABLE_DYNLOADING
     448             : #define uno_ext_getMapping java_uno_ext_getMapping
     449             : #endif
     450             : 
     451             : 
     452           6 : SAL_DLLPUBLIC_EXPORT void SAL_CALL uno_ext_getMapping(
     453             :     uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
     454             :     SAL_THROW_EXTERN_C()
     455             : {
     456             :     assert(ppMapping != 0);
     457             :     assert(pFrom != 0);
     458             :     assert(pTo != 0);
     459           6 :     if (0 != *ppMapping)
     460             :     {
     461           0 :         (*(*ppMapping)->release)( *ppMapping );
     462           0 :         *ppMapping = 0;
     463             :     }
     464             : 
     465             :     BOOST_STATIC_ASSERT( JNI_FALSE == sal_False );
     466             :     BOOST_STATIC_ASSERT( JNI_TRUE == sal_True );
     467             :     BOOST_STATIC_ASSERT( sizeof (jboolean) == sizeof (sal_Bool) );
     468             :     BOOST_STATIC_ASSERT( sizeof (jchar) == sizeof (sal_Unicode) );
     469             :     BOOST_STATIC_ASSERT( sizeof (jdouble) == sizeof (double) );
     470             :     BOOST_STATIC_ASSERT( sizeof (jfloat) == sizeof (float) );
     471             :     BOOST_STATIC_ASSERT( sizeof (jbyte) == sizeof (sal_Int8) );
     472             :     BOOST_STATIC_ASSERT( sizeof (jshort) == sizeof (sal_Int16) );
     473             :     BOOST_STATIC_ASSERT( sizeof (jint) == sizeof (sal_Int32) );
     474             :     BOOST_STATIC_ASSERT( sizeof (jlong) == sizeof (sal_Int64) );
     475             : 
     476             :     OUString const & from_env_typename =
     477           6 :         OUString::unacquired( &pFrom->pTypeName );
     478             :     OUString const & to_env_typename =
     479           6 :         OUString::unacquired( &pTo->pTypeName );
     480             : 
     481           6 :     uno_Mapping * mapping = 0;
     482             : 
     483             :     try
     484             :     {
     485           6 :         if ( from_env_typename == UNO_LB_JAVA && to_env_typename == UNO_LB_UNO )
     486             :         {
     487             :             Bridge * bridge =
     488           6 :                 new Bridge( pFrom, pTo->pExtEnv, true ); // ref count = 1
     489           6 :             mapping = &bridge->m_java2uno;
     490             :             uno_registerMapping(
     491             :                 &mapping, Bridge_free,
     492           6 :                 pFrom, (uno_Environment *)pTo->pExtEnv, 0 );
     493             :         }
     494           0 :         else if ( from_env_typename == UNO_LB_UNO && to_env_typename == UNO_LB_JAVA )
     495             :         {
     496             :             Bridge * bridge =
     497           0 :                 new Bridge( pTo, pFrom->pExtEnv, false ); // ref count = 1
     498           0 :             mapping = &bridge->m_uno2java;
     499             :             uno_registerMapping(
     500             :                 &mapping, Bridge_free,
     501           0 :                 (uno_Environment *)pFrom->pExtEnv, pTo, 0 );
     502             :         }
     503             :     }
     504           0 :     catch (const BridgeRuntimeError & err)
     505             :     {
     506             :         SAL_WARN(
     507             :             "bridges",
     508             :             "ingoring BridgeRuntimeError \"" << err.m_message << "\"");
     509             :     }
     510           0 :     catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
     511             :     {
     512             :         SAL_WARN("bridges", "attaching current thread to java failed");
     513             :     }
     514             : 
     515           6 :     *ppMapping = mapping;
     516           6 : }
     517             : 
     518             : }
     519             : 
     520             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10