Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/bridges/source/jni_uno/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 22 kB image not shown  

Quelle  jni_java2uno.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */


#include <sal/config.h>
#include <sal/log.hxx>

#include <algorithm>
#include <cassert>

#include "jni_bridge.h"
#include "jni_helper.h"
#include "jniunoenvironmentdata.hxx"

#include <com/sun/star/uno/Exception.hpp>

namespace jni_uno
{


jobject Bridge::map_to_java(
    JNI_context const & jni,
    uno_Interface * pUnoI, JNI_interface_type_info const * info ) const
{
    // get oid
    rtl_uString * pOid = nullptr;
    (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI );
    assert( pOid != nullptr );
    OUString oid( pOid, SAL_NO_ACQUIRE );

    // opt getRegisteredInterface()
    JLocalAutoRef jo_oid( jni, ustring_to_jstring( jni, oid.pData ) );
    jvalue args[ 2 ];
    args[ 0 ].l = jo_oid.get();
    args[ 1 ].l = info->m_type;
    jobject jo_iface = jni->CallObjectMethodA(
        getJniInfo()->m_object_java_env,
        getJniInfo()->m_method_IEnvironment_getRegisteredInterface, args );
    jni.ensure_no_exception();

    if (jo_iface == nullptr) // no registered iface
    {
        // register uno interface
        (*m_uno_env->registerInterface)(
            m_uno_env, reinterpret_castvoid ** >( &pUnoI ),
            oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(info->m_td.get()) );

        // create java and register java proxy
        jvalue args2[ 8 ];
        acquire();
        args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this );
        (*pUnoI->acquire)( pUnoI );
        args2[ 1 ].l = getJniInfo()->m_object_java_env;
        args2[ 2 ].j = reinterpret_cast< sal_Int64 >( pUnoI );
        typelib_typedescription_acquire( info->m_td.get() );
        args2[ 3 ].j = reinterpret_cast< sal_Int64 >( info->m_td.get() );
        args2[ 4 ].l = info->m_type;
        args2[ 5 ].l = jo_oid.get();
        args2[ 6 ].l = info->m_proxy_ctor;
        auto * envData = static_cast<jni_uno::JniUnoEnvironmentData *>(
            m_java_env->pContext);
        {
            std::unique_lock g(envData->mutex);
            args2[ 7 ].l = envData->asynchronousFinalizer;
        }
        jo_iface = jni->CallStaticObjectMethodA(
            getJniInfo()->m_class_JNI_proxy,
            getJniInfo()->m_method_JNI_proxy_create, args2 );
        jni.ensure_no_exception();
    }

    assert( jo_iface != nullptr );
    return jo_iface;
}


void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const
{
    if (uno_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION)
    {
#if OSL_DEBUG_LEVEL > 0
        // append java stack trace to Message member
        static_cast< css::uno::Exception * >(
            uno_exc->pData )->Message += jni.get_stack_trace();
#endif
        SAL_INFO(
            "bridges",
            "exception occurred java->uno: ["
                << OUString::unacquired(&uno_exc->pType->pTypeName) << "] "
                << static_cast<css::uno::Exception const *>(
                    uno_exc->pData)->Message);
        // signal exception
        jvalue java_exc;
        try
        {
            map_to_java(
                jni, &java_exc, uno_exc->pData, uno_exc->pType, nullptr,
                true /* in */, false /* no out */ );
        }
        catch (...)
        {
            uno_any_destruct( uno_exc, nullptr );
            throw;
        }
        uno_any_destruct( uno_exc, nullptr );

        JLocalAutoRef jo_exc( jni, java_exc.l );
        jint res = jni->Throwstatic_cast<jthrowable>(jo_exc.get()) );
        if (res != 0)
        {
            // call toString()
            JLocalAutoRef jo_descr(
                jni, jni->CallObjectMethodA(
                    jo_exc.get(), getJniInfo()->m_method_Object_toString, nullptr ) );
            jni.ensure_no_exception();
            throw BridgeRuntimeError(
                "throwing java exception failed: "
                + jstring_to_oustring( jni, static_cast<jstring>(jo_descr.get()) )
                + jni.get_stack_trace() );
        }
    }
    else
    {
        OUString message(
            "thrown exception is no uno exception: " +
            OUString::unacquired( &uno_exc->pType->pTypeName ) +
            jni.get_stack_trace() );
        uno_any_destruct( uno_exc, nullptr );
        throw BridgeRuntimeError( message );
    }
}

namespace {

union largest
{
    sal_Int64 n;
    double d;
    void * p;
    uno_Any a;
};

}

jobject Bridge::call_uno(
    JNI_context const & jni,
    uno_Interface * pUnoI, typelib_TypeDescription * member_td,
    typelib_TypeDescriptionReference * return_type,
    sal_Int32 nParams, typelib_MethodParameter const * pParams,
    jobjectArray jo_args /* may be 0 */ ) const
{
    // return mem
    sal_Int32 return_size;
    switch (return_type->eTypeClass) {
    case typelib_TypeClass_VOID:
        return_size = 0;
        break;

    case typelib_TypeClass_STRUCT:
    case typelib_TypeClass_EXCEPTION:
        return_size = std::max(
            TypeDescr(return_type).get()->nSize,
            static_cast< sal_Int32 >(sizeof (largest)));
        break;

    default:
        return_size = sizeof (largest);
        break;
    }

    char * mem = static_cast<char *>(alloca(
        (nParams * sizeof (void *)) +
        return_size + (nParams * sizeof (largest)) ));
    void ** uno_args = reinterpret_cast<void **>(mem);
    void * uno_ret = return_size == 0 ? nullptr : (mem + (nParams * sizeof (void *)));
    largest * uno_args_mem = reinterpret_cast<largest *>
        (mem + (nParams * sizeof (void *)) + return_size);

    assert( (nParams == 0) || (nParams == jni->GetArrayLength( jo_args )) );
    for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
    {
        typelib_MethodParameter const & param = pParams[ nPos ];
        typelib_TypeDescriptionReference * type = param.pTypeRef;

        uno_args[ nPos ] = &uno_args_mem[ nPos ];
        if (type->eTypeClass == typelib_TypeClass_STRUCT ||
            type->eTypeClass == typelib_TypeClass_EXCEPTION)
        {
            TypeDescr td( type );
            if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize)
                > sizeof (largest))
                uno_args[ nPos ] = alloca( td.get()->nSize );
        }

        if (param.bIn)
        {
            try
            {
                JLocalAutoRef jo_arg(
                    jni, jni->GetObjectArrayElement( jo_args, nPos ) );
                jni.ensure_no_exception();
                jvalue java_arg;
                java_arg.l = jo_arg.get();
                map_to_uno(
                    jni, uno_args[ nPos ], java_arg, type, nullptr,
                    false /* no assign */, param.bOut,
                    true /* special wrapped integral types */ );
            }
            catch (...)
            {
                // cleanup uno in args
                for ( sal_Int32 n = 0; n < nPos; ++n )
                {
                    typelib_MethodParameter const & p = pParams[ n ];
                    if (p.bIn)
                    {
                        uno_type_destructData(
                            uno_args[ n ], p.pTypeRef, nullptr );
                    }
                }
                throw;
            }
        }
    }

    uno_Any uno_exc_holder;
    uno_Any * uno_exc = &uno_exc_holder;
    // call binary uno
    (*pUnoI->pDispatcher)( pUnoI, member_td, uno_ret, uno_args, &uno_exc );

    if (uno_exc == nullptr)
    {
        // convert out args; destruct uno args
        for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
        {
            typelib_MethodParameter const & param = pParams[ nPos ];
            typelib_TypeDescriptionReference * type = param.pTypeRef;
            if (param.bOut)
            {
                try
                {
                    // get out holder array[ 1 ]
                    JLocalAutoRef jo_out_holder(
                        jni, jni->GetObjectArrayElement( jo_args, nPos ) );
                    jni.ensure_no_exception();
                    jvalue java_arg;
                    java_arg.l = jo_out_holder.get();
                    map_to_java(
                        jni, &java_arg, uno_args[ nPos ], type, nullptr,
                        true /* in */, true /* out holder */ );
                }
                catch (...)
                {
                    // cleanup further uno args
                    for ( sal_Int32 n = nPos; n < nParams; ++n )
                    {
                        uno_type_destructData(
                            uno_args[ n ], pParams[ n ].pTypeRef, nullptr );
                    }
                    // cleanup uno return value
                    uno_type_destructData( uno_ret, return_type, nullptr );
                    throw;
                }
            }
            if (typelib_TypeClass_DOUBLE < type->eTypeClass &&
                type->eTypeClass != typelib_TypeClass_ENUM) // opt
            {
                uno_type_destructData( uno_args[ nPos ], type, nullptr );
            }
        }

        if (return_type->eTypeClass != typelib_TypeClass_VOID)
        {
            // convert uno return value
            jvalue java_ret;
            try
            {
                map_to_java(
                    jni, &java_ret, uno_ret, return_type, nullptr,
                    true /* in */, false /* no out */,
                    true /* special_wrapped_integral_types */ );
            }
            catch (...)
            {
                uno_type_destructData( uno_ret, return_type, nullptr );
                throw;
            }
            if (typelib_TypeClass_DOUBLE < return_type->eTypeClass &&
                return_type->eTypeClass != typelib_TypeClass_ENUM) // opt
            {
                uno_type_destructData( uno_ret, return_type, nullptr );
            }
            return java_ret.l;
        }
        return nullptr; // void return
    }
    else // exception occurred
    {
        // destruct uno in args
        for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
        {
            typelib_MethodParameter const & param = pParams[ nPos ];
            if (param.bIn)
                uno_type_destructData( uno_args[ nPos ], param.pTypeRef, nullptr );
        }

        handle_uno_exc( jni, uno_exc );
        return nullptr;
    }
}

}

using namespace ::jni_uno;

extern "C"
{


SAL_JNI_EXPORT jobject
JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
    JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring jo_method,
    jobjectArray jo_args /* may be 0 */ )
{
    Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
    JNI_info const * jni_info = bridge->getJniInfo();
    JNI_context jni(
        jni_info, jni_env,
        static_cast< jobject >(
            static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
            ->machine->getClassLoader()));

    OUString method_name;

    try
    {
        method_name = jstring_to_oustring( jni, jo_method );
        SAL_INFO(
            "bridges",
            "java->uno call: " << method_name << " on oid "
            << jstring_to_oustring(
                jni,
                static_cast<jstring>(
                    JLocalAutoRef(
                        jni,
                        jni->GetObjectField(
                            jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
                    .get())));
        // special IQueryInterface.queryInterface()
        if ( method_name == "queryInterface" )
        {
            // oid
            JLocalAutoRef jo_oid(
                jni, jni->GetObjectField(
                    jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) );
            // type
            JLocalAutoRef jo_type(
                jni, jni->GetObjectArrayElement( jo_args, 0 ) );
            jni.ensure_no_exception();

            JLocalAutoRef jo_type_name(
                jni, jni->GetObjectField(
                    jo_type.get(), jni_info->m_field_Type_typeName ) );
            if (! jo_type_name.is())
            {
                throw BridgeRuntimeError(
                    "incomplete type object: no type name!" +
                    jni.get_stack_trace() );
            }
            OUString type_name(
                jstring_to_oustring( jni, static_cast<jstring>(jo_type_name.get()) ) );
            JNI_type_info const * info =
                jni_info->get_type_info( jni, type_name );
            if (info->m_td.get()->eTypeClass != typelib_TypeClass_INTERFACE)
            {
                throw BridgeRuntimeError(
                    u"queryInterface() call demands an INTERFACE type!"_ustr );
            }
            JNI_interface_type_info const * iface_info =
                static_cast< JNI_interface_type_info const * >( info );

            // getRegisteredInterface() already tested in JNI_proxy:
            // perform queryInterface call on binary uno interface
            uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
                jni->GetLongField(
                    jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );

            uno_Any uno_ret;
            void * uno_args[] = { &iface_info->m_td.get()->pWeakRef };
            uno_Any uno_exc_holder;
            uno_Any * uno_exc = &uno_exc_holder;
            // call binary uno
            (*pUnoI->pDispatcher)(
                pUnoI, jni_info->m_XInterface_queryInterface_td.get(),
                &uno_ret, uno_args, &uno_exc );
            if (uno_exc == nullptr)
            {
                jobject jo_ret = nullptr;
                if (uno_ret.pType->eTypeClass == typelib_TypeClass_INTERFACE)
                {
                    uno_Interface * pUnoRet =
                        static_cast<uno_Interface *>(uno_ret.pReserved);
                    if (pUnoRet != nullptr)
                    {
                        try
                        {
                            jo_ret =
                                bridge->map_to_java( jni, pUnoRet, iface_info );
                        }
                        catch (...)
                        {
                            uno_any_destruct( &uno_ret, nullptr );
                            throw;
                        }
                    }
                }
                uno_any_destruct( &uno_ret, nullptr );
                return jo_ret;
            }
            else
            {
                bridge->handle_uno_exc( jni, uno_exc );
                return nullptr;
            }
        }

        typelib_InterfaceTypeDescription * td =
            reinterpret_cast< typelib_InterfaceTypeDescription * >(
                jni->GetLongField(
                    jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
        uno_Interface * pUnoI =
            reinterpret_cast< uno_Interface * >(
                jni->GetLongField(
                    jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );

        typelib_TypeDescriptionReference ** ppAllMembers = td->ppAllMembers;
        for ( sal_Int32 nPos = td->nAllMembers; nPos--; )
        {
            // try to avoid getting typedescription as long as possible,
            // because of a Mutex.acquire() in
            // typelib_typedescriptionreference_getDescription()
            typelib_TypeDescriptionReference * member_type =
                ppAllMembers[ nPos ];

            // check method_name against fully qualified type_name
            // of member_type; type_name is of the form
            //  <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
            OUString const & type_name =
                OUString::unacquired( &member_type->pTypeName );
            sal_Int32 offset = type_name.indexOf( ':' ) + 2;
            assert(offset >= 2);
            assert(offset < type_name.getLength());
            assert(type_name[offset - 1] == ':' );
            sal_Int32 remainder = type_name.getLength() - offset;
            if (member_type->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
            {
                if ((method_name.getLength() == remainder
                     || (method_name.getLength() < remainder
                         && type_name[offset + method_name.getLength()] == ':'))
                    && type_name.match(method_name, offset))
                {
                    TypeDescr member_td( member_type );
                    typelib_InterfaceMethodTypeDescription * method_td =
                        reinterpret_cast<
                          typelib_InterfaceMethodTypeDescription * >(
                              member_td.get() );
                    return bridge->call_uno(
                        jni, pUnoI, member_td.get(),
                        method_td->pReturnTypeRef,
                        method_td->nParams, method_td->pParams,
                        jo_args );
                }
            }
            else // attribute
            {
                assert(
                    member_type->eTypeClass ==
                      typelib_TypeClass_INTERFACE_ATTRIBUTE );

                if (method_name.getLength() >= 3
                    && (method_name.getLength() - 3 == remainder
                        || (method_name.getLength() - 3 < remainder
                            && type_name[
                                offset + (method_name.getLength() - 3)] == ':'))
                    && method_name[1] == 'e' && method_name[2] == 't'
                    && rtl_ustr_compare_WithLength(
                        type_name.getStr() + offset,
                        method_name.getLength() - 3,
                        method_name.getStr() + 3,
                        method_name.getLength() - 3) == 0)
                {
                    if (method_name[ 0 ] == 'g')
                    {
                        TypeDescr member_td( member_type );
                        typelib_InterfaceAttributeTypeDescription * attr_td =
                            reinterpret_cast<
                              typelib_InterfaceAttributeTypeDescription * >(
                                  member_td.get() );
                        return bridge->call_uno(
                            jni, pUnoI, member_td.get(),
                            attr_td->pAttributeTypeRef,
                            0, nullptr,
                            jo_args );
                    }
                    else if (method_name[ 0 ] == 's')
                    {
                        TypeDescr member_td( member_type );
                        typelib_InterfaceAttributeTypeDescription * attr_td =
                            reinterpret_cast<
                              typelib_InterfaceAttributeTypeDescription * >(
                                  member_td.get() );
                        if (! attr_td->bReadOnly)
                        {
                            typelib_MethodParameter param;
                            param.pTypeRef = attr_td->pAttributeTypeRef;
                            param.bIn = true;
                            param.bOut = false;
                            return bridge->call_uno(
                                jni, pUnoI, member_td.get(),
                                jni_info->m_void_type.getTypeLibType(),
                                1, ¶m,
                                jo_args );
                        }
                    }
                }
            }
        }
        // the thing that should not be... no method info found!
        throw BridgeRuntimeError(
            "calling undeclared function on interface "
            + OUString::unacquired(&td->aBase.pTypeName)
            + ": " + method_name + jni.get_stack_trace() );
    }
    catch (const BridgeRuntimeError & err)
    {
        SAL_WARN(
            "bridges",
            "Java calling UNO method " << method_name << ": " << err.m_message);
        // notify RuntimeException
        OString cstr_msg(
            "[jni_uno bridge error] Java calling UNO method "
            + OUStringToOString(method_name, RTL_TEXTENCODING_JAVA_UTF8) + ": "
            + OUStringToOString(err.m_message, RTL_TEXTENCODING_JAVA_UTF8));
        if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
            != 0)
        {
            assert( false );
        }
        return nullptr;
    }
    catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException &)
    {
        SAL_WARN("bridges""attaching current thread to java failed");
        OString cstr_msg(
            "[jni_uno bridge error] attaching current thread to java failed"
            + OUStringToOString(
                jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8));
        if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr())
            != 0)
        {
            assert( false );
        }
        return nullptr;
    }
}


SAL_JNI_EXPORT void
JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
    JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle )
{
    Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle );
    JNI_info const * jni_info = bridge->getJniInfo();
    JNI_context jni(
        jni_info, jni_env,
        static_cast< jobject >(
            static_cast<JniUnoEnvironmentData *>(bridge->m_java_env->pContext)
            ->machine->getClassLoader()));

    uno_Interface * pUnoI = reinterpret_cast< uno_Interface * >(
        jni->GetLongField(
            jo_proxy, jni_info->m_field_JNI_proxy_m_receiver_handle ) );
    typelib_TypeDescription * td =
        reinterpret_cast< typelib_TypeDescription * >(
            jni->GetLongField(
                jo_proxy, jni_info->m_field_JNI_proxy_m_td_handle ) );
    SAL_INFO(
        "bridges",
        "freeing java uno proxy: "
            << jstring_to_oustring(
                jni,
                static_cast<jstring>(
                    JLocalAutoRef(
                        jni,
                        jni->GetObjectField(
                            jo_proxy, jni_info->m_field_JNI_proxy_m_oid))
                    .get())));
    // revoke from uno env; has already been revoked from java env
    (*bridge->m_uno_env->revokeInterface)( bridge->m_uno_env, pUnoI );
    // release receiver
    (*pUnoI->release)( pUnoI );
    // release typedescription handle
    typelib_typedescription_release( td );
    // release bridge handle
    bridge->release();
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=96 H=89 G=92

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.