diff options
Diffstat (limited to 'bridges/source/jni_uno')
-rw-r--r-- | bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java | 52 | ||||
-rw-r--r-- | bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java | 218 | ||||
-rw-r--r-- | bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/makefile.mk | 53 | ||||
-rw-r--r-- | bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest | 1 | ||||
-rw-r--r-- | bridges/source/jni_uno/java_uno.map | 27 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_base.h | 295 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_bridge.cxx | 569 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_bridge.h | 127 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_data.cxx | 2579 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_helper.h | 165 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_info.cxx | 999 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_info.h | 378 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_java2uno.cxx | 706 | ||||
-rw-r--r-- | bridges/source/jni_uno/jni_uno2java.cxx | 875 | ||||
-rw-r--r-- | bridges/source/jni_uno/makefile.mk | 86 | ||||
-rw-r--r-- | bridges/source/jni_uno/nativethreadpool.cxx | 233 |
16 files changed, 7363 insertions, 0 deletions
diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java new file mode 100644 index 000000000000..223b53a7013f --- /dev/null +++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_info_holder.java @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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. + * + ************************************************************************/ + +package com.sun.star.bridges.jni_uno; + +import com.sun.star.lib.util.NativeLibraryLoader; + +//============================================================================== +public final class JNI_info_holder +{ + static { + NativeLibraryLoader.loadLibrary(JNI_info_holder.class.getClassLoader(), + "java_uno"); + } + + private static JNI_info_holder s_holder = new JNI_info_holder(); + + private static long s_jni_info_handle; + + //__________________________________________________________________________ + private native void finalize( long jni_info_handle ); + + //__________________________________________________________________________ + protected void finalize() + { + finalize( s_jni_info_handle ); + } +} diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java new file mode 100644 index 000000000000..076d568e9c91 --- /dev/null +++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/JNI_proxy.java @@ -0,0 +1,218 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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. + * + ************************************************************************/ + +package com.sun.star.bridges.jni_uno; + +import com.sun.star.lib.util.AsynchronousFinalizer; +import com.sun.star.lib.util.NativeLibraryLoader; +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.IEnvironment; +import com.sun.star.uno.IQueryInterface; + + +//============================================================================== +public final class JNI_proxy implements java.lang.reflect.InvocationHandler +{ + static { + NativeLibraryLoader.loadLibrary(JNI_proxy.class.getClassLoader(), + "java_uno"); + } + protected static ClassLoader s_classloader = + JNI_proxy.class.getClassLoader(); + protected static Class s_InvocationHandler [] = + new Class [] { java.lang.reflect.InvocationHandler.class }; + + protected long m_bridge_handle; + protected IEnvironment m_java_env; + protected long m_receiver_handle; + protected long m_td_handle; + protected Type m_type; + protected String m_oid; + protected Class m_class; + + //__________________________________________________________________________ + public static String get_stack_trace( Throwable throwable ) + throws Throwable + { + boolean current_trace = false; + if (null == throwable) + { + throwable = new Throwable(); + current_trace = true; + } + java.io.StringWriter string_writer = + new java.io.StringWriter(); + java.io.PrintWriter print_writer = + new java.io.PrintWriter( string_writer, true ); + throwable.printStackTrace( print_writer ); + print_writer.flush(); + print_writer.close(); + string_writer.flush(); + String trace = string_writer.toString(); + if (current_trace) + { + // cut out first two lines + int n = trace.indexOf( '\n' ); + n = trace.indexOf( '\n', n +1 ); + trace = trace.substring( n +1 ); + } + return "\njava stack trace:\n" + trace; + } + + //__________________________________________________________________________ + private native void finalize( long bridge_handle ); + + //__________________________________________________________________________ + public void finalize() + { + AsynchronousFinalizer.add(new AsynchronousFinalizer.Job() { + public void run() throws Throwable { + JNI_proxy.this.finalize( m_bridge_handle ); + } + }); + } + + //__________________________________________________________________________ + private JNI_proxy( + long bridge_handle, IEnvironment java_env, + long receiver_handle, long td_handle, Type type, String oid ) + { + m_bridge_handle = bridge_handle; + m_java_env = java_env; + m_receiver_handle = receiver_handle; + m_td_handle = td_handle; + m_type = type; + m_oid = oid; + m_class = m_type.getZClass(); + } + + //__________________________________________________________________________ + public static Object create( + long bridge_handle, IEnvironment java_env, + long receiver_handle, long td_handle, Type type, String oid, + java.lang.reflect.Constructor proxy_ctor ) + throws Throwable + { + JNI_proxy handler = new JNI_proxy( + bridge_handle, java_env, receiver_handle, td_handle, type, oid ); + Object proxy = proxy_ctor.newInstance( new Object [] { handler } ); + return java_env.registerInterface( proxy, new String [] { oid }, type ); + } + + //__________________________________________________________________________ + public static java.lang.reflect.Constructor get_proxy_ctor( Class clazz ) + throws Throwable + { + Class proxy_class = java.lang.reflect.Proxy.getProxyClass( + s_classloader, + new Class [] { clazz, IQueryInterface.class, + com.sun.star.lib.uno.Proxy.class } ); + return proxy_class.getConstructor( s_InvocationHandler ); + } + + //__________________________________________________________________________ + private native Object dispatch_call( + long bridge_handle, String decl_class, String method, Object args [] ) + throws Throwable; + + // InvocationHandler impl + //__________________________________________________________________________ + public Object invoke( + Object proxy, java.lang.reflect.Method method, Object args [] ) + throws Throwable + { + Class decl_class = method.getDeclaringClass(); + String method_name = method.getName(); + + if (Object.class.equals( decl_class )) + { + if (method_name.equals( "hashCode" )) + { + // int hashCode() + return new Integer( m_oid.hashCode() ); + } + else if (method_name.equals( "equals" )) + { + // boolean equals( Object obj ) + return isSame(args[0]); + } + else if (method_name.equals( "toString" )) + { + // String toString() + return this.toString() + " [oid=" + m_oid + + ", type=" + m_type.getTypeName() + "]"; + } + } + // UNO interface call + else if (decl_class.isAssignableFrom( m_class )) + { + // dispatch interface call + return dispatch_call( + m_bridge_handle, decl_class.getName(), method_name, args ); + } + // IQueryInterface impl + else if (IQueryInterface.class.equals( decl_class )) + { + if (method_name.equals( "queryInterface" )) + { + // Object queryInterface( Type type ) + Object registered_proxy = + m_java_env.getRegisteredInterface( m_oid, (Type)args[ 0 ] ); + if (null == registered_proxy) + { + return dispatch_call( + m_bridge_handle, + "com.sun.star.uno.XInterface", method_name, args ); + } + else + { + return registered_proxy; + } + } + else if (method_name.equals( "isSame" )) + { + // boolean isSame( Object object ) + return isSame(args[0]); + } + else if (method_name.equals( "getOid" )) + { + // String getOid() + return m_oid; + } + } + + throw new com.sun.star.uno.RuntimeException( + "[jni_uno bridge error] unexpected call on proxy " + + proxy.toString() + ": " + method.toString() ); + } + + private Boolean isSame(Object obj) { + return new Boolean(obj != null + && m_oid.equals(UnoRuntime.generateOid(obj))); + } +} diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/makefile.mk b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/makefile.mk new file mode 100644 index 000000000000..5d3eb9fea1f5 --- /dev/null +++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/makefile.mk @@ -0,0 +1,53 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# 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. +# +#************************************************************************* +PRJ=..$/..$/..$/..$/..$/..$/..$/.. + +PRJNAME=bridges +TARGET=java_uno +PACKAGE=com$/sun$/star$/bridges$/jni_uno + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +JARFILES=jurt.jar ridl.jar +JAVAFILES=$(subst,$(CLASSDIR)$/$(PACKAGE)$/, $(subst,.class,.java $(JAVACLASSFILES))) + +JAVACLASSFILES= \ + $(CLASSDIR)$/$(PACKAGE)$/JNI_proxy.class \ + $(CLASSDIR)$/$(PACKAGE)$/JNI_info_holder.class + +JARCLASSDIRS=$(PACKAGE) +JARTARGET=$(TARGET).jar +JARCOMPRESS=TRUE +JARCLASSPATH = $(JARFILES) ../../lib/ ../bin/ +CUSTOMMANIFESTFILE = manifest + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest new file mode 100644 index 000000000000..7ad02e156d9a --- /dev/null +++ b/bridges/source/jni_uno/java/com/sun/star/bridges/jni_uno/manifest @@ -0,0 +1 @@ +Sealed: true diff --git a/bridges/source/jni_uno/java_uno.map b/bridges/source/jni_uno/java_uno.map new file mode 100644 index 000000000000..376f7ea979bb --- /dev/null +++ b/bridges/source/jni_uno/java_uno.map @@ -0,0 +1,27 @@ +UDK_3_0_0 { + global: + uno_initEnvironment; + uno_ext_getMapping; + component_canUnload; + local: + *; +}; + +UDK_3.1 { + global: + Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J; + Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call; + Java_com_sun_star_bridges_jni_1uno_JNI_1info_1holder_finalize__J; +} UDK_3_0_0; + +UDK_3.2 { + global: + Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_attach; + Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_create; + Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_destroy; + Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_detach; + Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_dispose; + Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_enter; + Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_threadId; + Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_putJob; +} UDK_3.1; diff --git a/bridges/source/jni_uno/jni_base.h b/bridges/source/jni_uno/jni_base.h new file mode 100644 index 000000000000..cc23cd1b2a8f --- /dev/null +++ b/bridges/source/jni_uno/jni_base.h @@ -0,0 +1,295 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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. + * + ************************************************************************/ + +#if ! defined INCLUDED_JNI_BASE_H +#define INCLUDED_JNI_BASE_H + +#if defined (__SUNPRO_CC) || defined (__SUNPRO_C) +// workaround solaris include trouble on jumbo +#include <stdarg.h> +namespace std +{ +typedef __va_list va_list; +} +#endif +#include <memory> + +#include "jvmaccess/unovirtualmachine.hxx" +#include "jvmaccess/virtualmachine.hxx" + +#include "osl/diagnose.h" + +#include "rtl/alloc.h" +#include "rtl/ustring.hxx" + +#include "uno/environment.h" +#include "typelib/typedescription.h" + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + + +namespace jni_uno +{ + +class JNI_info; + +//============================================================================== +struct BridgeRuntimeError +{ + ::rtl::OUString m_message; + + inline BridgeRuntimeError( ::rtl::OUString const & message ) + : m_message( message ) + {} +}; + + +//============================================================================== +class JNI_context +{ + JNI_info const * m_jni_info; + JNIEnv * m_env; + jobject m_class_loader; + + JNI_context( JNI_context & ); // not impl + void operator = ( JNI_context ); // not impl + + void java_exc_occurred() const; +public: + inline explicit JNI_context( + JNI_info const * jni_info, JNIEnv * env, jobject class_loader ) + : m_jni_info( jni_info ), + m_env( env ), + m_class_loader( class_loader ) + {} + + inline JNI_info const * get_info() const + { return m_jni_info; } + + inline JNIEnv * operator -> () const + { return m_env; } + inline JNIEnv * get_jni_env() const + { return m_env; } + + // does not handle exceptions, *classClass will be null if exception + // occurred: + void getClassForName(jclass * classClass, jmethodID * methodForName) const; + + // if inException, does not handle exceptions, in which case returned value + // will be null if exception occurred: + jclass findClass( + char const * name, jclass classClass, jmethodID methodForName, + bool inException) const; + + inline void ensure_no_exception() const; // throws BridgeRuntimeError + inline bool assert_no_exception() const; // asserts and clears exception + + ::rtl::OUString get_stack_trace( jobject jo_exc = 0 ) const; +}; + +//______________________________________________________________________________ +inline void JNI_context::ensure_no_exception() const +{ + if (JNI_FALSE != m_env->ExceptionCheck()) + { + java_exc_occurred(); + } +} + +//______________________________________________________________________________ +inline bool JNI_context::assert_no_exception() const +{ + if (JNI_FALSE != m_env->ExceptionCheck()) + { + m_env->ExceptionClear(); + OSL_FAIL( "unexpected java exception occurred!" ); + return false; + } + return true; +} + + +//============================================================================== +class JNI_guarded_context + : private ::jvmaccess::VirtualMachine::AttachGuard, + public JNI_context +{ + JNI_guarded_context( JNI_guarded_context & ); // not impl + void operator = ( JNI_guarded_context ); // not impl + +public: + inline explicit JNI_guarded_context( + JNI_info const * jni_info, ::jvmaccess::UnoVirtualMachine * vm_access ) + : AttachGuard( vm_access->getVirtualMachine() ), + JNI_context( + jni_info, AttachGuard::getEnvironment(), + static_cast< jobject >(vm_access->getClassLoader()) ) + {} +}; + + +//============================================================================== +class JLocalAutoRef +{ + JNI_context const & m_jni; + jobject m_jo; + +public: + inline JLocalAutoRef( JNI_context const & jni ) + : m_jni( jni ), + m_jo( 0 ) + {} + inline explicit JLocalAutoRef( JNI_context const & jni, jobject jo ) + : m_jni( jni ), + m_jo( jo ) + {} + inline JLocalAutoRef( JLocalAutoRef & auto_ref ); + inline ~JLocalAutoRef() SAL_THROW( () ); + + inline jobject get() const + { return m_jo; } + inline bool is() const + { return (0 != m_jo); } + inline jobject release(); + inline void reset(); + inline void reset( jobject jo ); + inline JLocalAutoRef & operator = ( JLocalAutoRef & auto_ref ); +}; + +//______________________________________________________________________________ +inline JLocalAutoRef::~JLocalAutoRef() SAL_THROW( () ) +{ + if (0 != m_jo) + m_jni->DeleteLocalRef( m_jo ); +} + +//______________________________________________________________________________ +inline JLocalAutoRef::JLocalAutoRef( JLocalAutoRef & auto_ref ) + : m_jni( auto_ref.m_jni ), + m_jo( auto_ref.m_jo ) +{ + auto_ref.m_jo = 0; +} + +//______________________________________________________________________________ +inline jobject JLocalAutoRef::release() +{ + jobject jo = m_jo; + m_jo = 0; + return jo; +} + +//______________________________________________________________________________ +inline void JLocalAutoRef::reset() +{ + if (0 != m_jo) + m_jni->DeleteLocalRef( m_jo ); + m_jo = 0; +} + +//______________________________________________________________________________ +inline void JLocalAutoRef::reset( jobject jo ) +{ + if (jo != m_jo) + { + if (0 != m_jo) + m_jni->DeleteLocalRef( m_jo ); + m_jo = jo; + } +} + +//______________________________________________________________________________ +inline JLocalAutoRef & JLocalAutoRef::operator = ( JLocalAutoRef & auto_ref ) +{ + OSL_ASSERT( m_jni.get_jni_env() == auto_ref.m_jni.get_jni_env() ); + reset( auto_ref.m_jo ); + auto_ref.m_jo = 0; + return *this; +} + + +//============================================================================== +struct rtl_mem +{ + inline static void * operator new ( size_t nSize ) + { return rtl_allocateMemory( nSize ); } + inline static void operator delete ( void * mem ) + { if (mem) rtl_freeMemory( mem ); } + inline static void * operator new ( size_t, void * mem ) + { return mem; } + inline static void operator delete ( void *, void * ) + {} + + static inline ::std::auto_ptr< rtl_mem > allocate( ::std::size_t bytes ); +}; + +//______________________________________________________________________________ +inline ::std::auto_ptr< rtl_mem > rtl_mem::allocate( ::std::size_t bytes ) +{ + void * p = rtl_allocateMemory( bytes ); + if (0 == p) + throw BridgeRuntimeError( OUSTR("out of memory!") ); + return ::std::auto_ptr< rtl_mem >( (rtl_mem *)p ); +} + + +//============================================================================== +class TypeDescr +{ + typelib_TypeDescription * m_td; + + TypeDescr( TypeDescr & ); // not impl + void operator = ( TypeDescr ); // not impl + +public: + inline explicit TypeDescr( typelib_TypeDescriptionReference * td_ref ); + inline ~TypeDescr() SAL_THROW( () ) + { TYPELIB_DANGER_RELEASE( m_td ); } + + inline typelib_TypeDescription * get() const + { return m_td; } +}; + +//______________________________________________________________________________ +inline TypeDescr::TypeDescr( typelib_TypeDescriptionReference * td_ref ) + : m_td( 0 ) +{ + TYPELIB_DANGER_GET( &m_td, td_ref ); + if (0 == m_td) + { + throw BridgeRuntimeError( + OUSTR("cannot get comprehensive type description for ") + + ::rtl::OUString::unacquired( &td_ref->pTypeName ) ); + } +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/jni_uno/jni_bridge.cxx b/bridges/source/jni_uno/jni_bridge.cxx new file mode 100644 index 000000000000..d15f05a814fd --- /dev/null +++ b/bridges/source/jni_uno/jni_bridge.cxx @@ -0,0 +1,569 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_FAIL( cstr_msg.getStr() ); +#else + (void) err; // unused +#endif + } + catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) + { + OSL_FAIL( + "[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_FAIL( cstr_msg.getStr() ); +#else + (void) err; // unused +#endif + } + catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) + { + OSL_FAIL( + "[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_occurred() 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 occurred, 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_FAIL( cstr_msg.getStr() ); +#else + (void) err; // unused +#endif + } + catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) + { + OSL_FAIL( + "[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 ); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/jni_uno/jni_bridge.h b/bridges/source/jni_uno/jni_bridge.h new file mode 100644 index 000000000000..f2298fbdbe46 --- /dev/null +++ b/bridges/source/jni_uno/jni_bridge.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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. + * + ************************************************************************/ + +#if ! defined INCLUDED_JNI_BRIDGE_H +#define INCLUDED_JNI_BRIDGE_H + +#include "jni_base.h" +#include "jni_info.h" +#include "jni_helper.h" + +#include "osl/diagnose.h" +#include "osl/interlck.h" + +#include "uno/mapping.h" +#include "uno/dispatcher.h" + +#include "com/sun/star/uno/XInterface.hpp" + + +namespace jni_uno +{ + +//==== holds environments and mappings ========================================= +struct Bridge; +struct Mapping : public uno_Mapping +{ + Bridge * m_bridge; +}; + +//============================================================================== +struct Bridge +{ + mutable oslInterlockedCount m_ref; + + uno_ExtEnvironment * m_uno_env; + uno_Environment * m_java_env; + + Mapping m_java2uno; + Mapping m_uno2java; + bool m_registered_java2uno; + + JNI_info const * m_jni_info; + + // + ~Bridge() SAL_THROW( () ); + explicit Bridge( + uno_Environment * java_env, uno_ExtEnvironment * uno_env, + bool registered_java2uno ); + + void acquire() const; + void release() const; + + // jni_data.cxx + void map_to_uno( + JNI_context const & jni, + void * uno_data, jvalue java_data, + typelib_TypeDescriptionReference * type, + JNI_type_info const * info /* maybe 0 */, + bool assign, bool out_param, + bool special_wrapped_integral_types = false ) const; + void map_to_java( + JNI_context const & jni, + jvalue * java_data, void const * uno_data, + typelib_TypeDescriptionReference * type, + JNI_type_info const * info /* maybe 0 */, + bool in_param, bool out_param, + bool special_wrapped_integral_types = false ) const; + + // jni_uno2java.cxx + void handle_uno_exc( + JNI_context const & jni, uno_Any * uno_exc ) const; + void call_java( + jobject javaI, + typelib_InterfaceTypeDescription * iface_td, + sal_Int32 local_member_index, sal_Int32 function_pos_offset, + typelib_TypeDescriptionReference * return_type, + typelib_MethodParameter * params, sal_Int32 nParams, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const; + jobject map_to_java( + JNI_context const & jni, + uno_Interface * pUnoI, JNI_interface_type_info const * info ) const; + + // jni_java2uno.cxx + void handle_java_exc( + JNI_context const & jni, + JLocalAutoRef const & jo_exc, uno_Any * uno_exc ) const; + jobject call_uno( + JNI_context const & jni, + uno_Interface * pUnoI, typelib_TypeDescription * member_td, + typelib_TypeDescriptionReference * return_tdref, + sal_Int32 nParams, typelib_MethodParameter const * pParams, + jobjectArray jo_args ) const; + uno_Interface * map_to_uno( + JNI_context const & jni, + jobject javaI, JNI_interface_type_info const * info ) const; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/jni_uno/jni_data.cxx b/bridges/source/jni_uno/jni_data.cxx new file mode 100644 index 000000000000..aca455d154ed --- /dev/null +++ b/bridges/source/jni_uno/jni_data.cxx @@ -0,0 +1,2579 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 "rtl/strbuf.hxx" +#include "rtl/ustrbuf.hxx" +#include "uno/sequence2.h" + + +using namespace ::std; +using namespace ::rtl; + +namespace jni_uno +{ + +//------------------------------------------------------------------------------ +inline rtl_mem * seq_allocate( sal_Int32 nElements, sal_Int32 nSize ) +{ + auto_ptr< rtl_mem > seq( + rtl_mem::allocate( SAL_SEQUENCE_HEADER_SIZE + (nElements * nSize) ) ); + uno_Sequence * p = (uno_Sequence *)seq.get(); + p->nRefCount = 1; + p->nElements = nElements; + return seq.release(); +} + +//______________________________________________________________________________ +namespace { + +void createDefaultUnoValue( + JNI_context const & jni, void * uno_data, + typelib_TypeDescriptionReference * type, + JNI_type_info const * info /* maybe 0 */, bool assign) +{ + switch (type->eTypeClass) { + case typelib_TypeClass_BOOLEAN: + *static_cast< sal_Bool * >(uno_data) = false; + break; + + case typelib_TypeClass_BYTE: + *static_cast< sal_Int8 * >(uno_data) = 0; + break; + + case typelib_TypeClass_SHORT: + *static_cast< sal_Int16 * >(uno_data) = 0; + break; + + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast< sal_uInt16 * >(uno_data) = 0; + break; + + case typelib_TypeClass_LONG: + *static_cast< sal_Int32 * >(uno_data) = 0; + break; + + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast< sal_uInt32 * >(uno_data) = 0; + break; + + case typelib_TypeClass_HYPER: + *static_cast< sal_Int64 * >(uno_data) = 0; + break; + + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast< sal_uInt64 * >(uno_data) = 0; + break; + + case typelib_TypeClass_FLOAT: + *static_cast< float * >(uno_data) = 0; + break; + + case typelib_TypeClass_DOUBLE: + *static_cast< double * >(uno_data) = 0; + break; + + case typelib_TypeClass_CHAR: + *static_cast< sal_Unicode * >(uno_data) = 0; + break; + + case typelib_TypeClass_STRING: + if (!assign) { + *static_cast< rtl_uString ** >(uno_data) = 0; + } + rtl_uString_new(static_cast< rtl_uString ** >(uno_data)); + break; + + case typelib_TypeClass_TYPE: + if (assign) { + typelib_typedescriptionreference_release( + *static_cast< typelib_TypeDescriptionReference ** >(uno_data)); + } + *static_cast< typelib_TypeDescriptionReference ** >(uno_data) + = *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID); + OSL_ASSERT( + *static_cast< typelib_TypeDescriptionReference ** >(uno_data) != 0); + typelib_typedescriptionreference_acquire( + *static_cast< typelib_TypeDescriptionReference ** >(uno_data)); + break; + + case typelib_TypeClass_ANY: + if (assign) { + uno_any_destruct(static_cast< uno_Any * >(uno_data), 0); + } + uno_any_construct( + static_cast< uno_Any * >(uno_data), 0, + jni.get_info()->m_XInterface_type_info->m_td.get(), 0); + break; + + case typelib_TypeClass_SEQUENCE: + { + auto_ptr< rtl_mem > seq(seq_allocate(0, 0)); + if (assign) { + uno_type_destructData(uno_data, type, 0); + } + *static_cast< uno_Sequence ** >(uno_data) + = reinterpret_cast< uno_Sequence * >(seq.release()); + break; + } + + case typelib_TypeClass_ENUM: + { + typelib_TypeDescription * td = 0; + TYPELIB_DANGER_GET(&td, type); + *static_cast< sal_Int32 * >(uno_data) + = (reinterpret_cast< typelib_EnumTypeDescription * >(td)-> + nDefaultEnumValue); + TYPELIB_DANGER_RELEASE(td); + break; + } + + case typelib_TypeClass_STRUCT: + { + if (info == 0) { + info = jni.get_info()->get_type_info(jni, type); + } + JNI_compound_type_info const * comp_info + = static_cast< JNI_compound_type_info const * >(info); + typelib_CompoundTypeDescription * comp_td + = reinterpret_cast< typelib_CompoundTypeDescription * >( + comp_info->m_td.get()); + sal_Int32 nPos = 0; + sal_Int32 nMembers = comp_td->nMembers; + try { + if (comp_td->pBaseTypeDescription != 0) { + createDefaultUnoValue( + jni, uno_data, + comp_td->pBaseTypeDescription->aBase.pWeakRef, + comp_info->m_base, assign); + } + for (; nPos < nMembers; ++nPos) { + createDefaultUnoValue( + jni, + (static_cast< char * >(uno_data) + + comp_td->pMemberOffsets[nPos]), + comp_td->ppTypeRefs[nPos], 0, assign); + } + } catch (...) { + if (!assign) { + for (sal_Int32 i = 0; i < nPos; ++i) { + uno_type_destructData( + (static_cast< char * >(uno_data) + + comp_td->pMemberOffsets[i]), + comp_td->ppTypeRefs[i], 0); + } + if (comp_td->pBaseTypeDescription != 0) { + uno_destructData( + uno_data, &comp_td->pBaseTypeDescription->aBase, 0); + } + } + throw; + } + } + break; + + case typelib_TypeClass_INTERFACE: + if (assign) { + uno_Interface * p = *static_cast< uno_Interface ** >(uno_data); + if (p != 0) { + (*p->release)(p); + } + } + *static_cast< uno_Interface ** >(uno_data) = 0; + break; + + default: + OSL_ASSERT(false); + break; + } +} + +} + +void Bridge::map_to_uno( + JNI_context const & jni, + void * uno_data, jvalue java_data, + typelib_TypeDescriptionReference * type, + JNI_type_info const * info /* maybe 0 */, + bool assign, bool out_param, + bool special_wrapped_integral_types ) const +{ + OSL_ASSERT( + !out_param || + (1 == jni->GetArrayLength( (jarray) java_data.l )) ); + + switch (type->eTypeClass) + { + case typelib_TypeClass_CHAR: + if (out_param) + { + jni->GetCharArrayRegion( + (jcharArray) java_data.l, 0, 1, (jchar *) uno_data ); + jni.ensure_no_exception(); + } + else if (special_wrapped_integral_types) + { + *(jchar *) uno_data = jni->CallCharMethodA( + java_data.l, m_jni_info->m_method_Character_charValue, 0 ); + jni.ensure_no_exception(); + } + else + { + *(jchar *) uno_data = java_data.c; + } + break; + case typelib_TypeClass_BOOLEAN: + if (out_param) + { + jni->GetBooleanArrayRegion( + (jbooleanArray) java_data.l, 0, 1, (jboolean *) uno_data ); + jni.ensure_no_exception(); + } + else if (special_wrapped_integral_types) + { + *(jboolean *) uno_data = jni->CallBooleanMethodA( + java_data.l, m_jni_info->m_method_Boolean_booleanValue, 0 ); + jni.ensure_no_exception(); + } + else + { + *(jboolean *) uno_data = java_data.z; + } + break; + case typelib_TypeClass_BYTE: + if (out_param) + { + jni->GetByteArrayRegion( + (jbyteArray) java_data.l, 0, 1, (jbyte *) uno_data ); + jni.ensure_no_exception(); + } + else if (special_wrapped_integral_types) + { + *(jbyte *) uno_data = jni->CallByteMethodA( + java_data.l, m_jni_info->m_method_Byte_byteValue, 0 ); + jni.ensure_no_exception(); + } + else + { + *(jbyte *) uno_data = java_data.b; + } + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + if (out_param) + { + jni->GetShortArrayRegion( + (jshortArray) java_data.l, 0, 1, (jshort *) uno_data ); + jni.ensure_no_exception(); + } + else if (special_wrapped_integral_types) + { + *(jshort *) uno_data = jni->CallShortMethodA( + java_data.l, m_jni_info->m_method_Short_shortValue, 0 ); + jni.ensure_no_exception(); + } + else + { + *(jshort *) uno_data = java_data.s; + } + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + if (out_param) + { + jni->GetIntArrayRegion( + (jintArray) java_data.l, 0, 1, (jint *) uno_data ); + jni.ensure_no_exception(); + } + else if (special_wrapped_integral_types) + { + *(jint *) uno_data = jni->CallIntMethodA( + java_data.l, m_jni_info->m_method_Integer_intValue, 0 ); + jni.ensure_no_exception(); + } + else + { + *(jint *) uno_data = java_data.i; + } + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (out_param) + { + jni->GetLongArrayRegion( + (jlongArray) java_data.l, 0, 1, (jlong *) uno_data ); + jni.ensure_no_exception(); + } + else if (special_wrapped_integral_types) + { + *(jlong *) uno_data = jni->CallLongMethodA( + java_data.l, m_jni_info->m_method_Long_longValue, 0 ); + jni.ensure_no_exception(); + } + else + { + *(jlong *) uno_data = java_data.j; + } + break; + case typelib_TypeClass_FLOAT: + if (out_param) + { + jni->GetFloatArrayRegion( + (jfloatArray) java_data.l, 0, 1, (jfloat *) uno_data ); + jni.ensure_no_exception(); + } + else if (special_wrapped_integral_types) + { + *(jfloat *) uno_data = jni->CallFloatMethodA( + java_data.l, m_jni_info->m_method_Float_floatValue, 0 ); + jni.ensure_no_exception(); + } + else + { + *(jfloat *) uno_data = java_data.f; + } + break; + case typelib_TypeClass_DOUBLE: + if (out_param) + { + jni->GetDoubleArrayRegion( + (jdoubleArray) java_data.l, 0, 1, (jdouble *) uno_data ); + jni.ensure_no_exception(); + } + else if (special_wrapped_integral_types) + { + *(jdouble *) uno_data = jni->CallDoubleMethodA( + java_data.l, m_jni_info->m_method_Double_doubleValue, 0 ); + jni.ensure_no_exception(); + } + else + { + *(jdouble *) uno_data = java_data.d; + } + break; + case typelib_TypeClass_STRING: + { + JLocalAutoRef jo_out_holder( jni ); + if (out_param) + { + jo_out_holder.reset( + jni->GetObjectArrayElement( (jobjectArray) java_data.l, 0 ) ); + jni.ensure_no_exception(); + java_data.l = jo_out_holder.get(); + } + if (0 == java_data.l) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] null-ref given!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + if (! assign) + *(rtl_uString **)uno_data = 0; + jstring_to_ustring( + jni, (rtl_uString **)uno_data, (jstring) java_data.l ); + break; + } + case typelib_TypeClass_TYPE: + { + JLocalAutoRef jo_out_holder( jni ); + if (out_param) + { + jo_out_holder.reset( + jni->GetObjectArrayElement( (jobjectArray) java_data.l, 0 ) ); + jni.ensure_no_exception(); + java_data.l = jo_out_holder.get(); + } + if (0 == java_data.l) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] null-ref given!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + + // type name + JLocalAutoRef jo_type_name( + jni, jni->GetObjectField( + java_data.l, m_jni_info->m_field_Type__typeName ) ); + if (! jo_type_name.is()) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("] incomplete type object: " + "no type name!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + OUString type_name( + jstring_to_oustring( jni, (jstring) jo_type_name.get() ) ); + ::com::sun::star::uno::TypeDescription td( type_name ); + if (! td.is()) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("] UNO type not found: ") ); + buf.append( type_name ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + typelib_typedescriptionreference_acquire( td.get()->pWeakRef ); + if (assign) + { + typelib_typedescriptionreference_release( + *(typelib_TypeDescriptionReference **)uno_data ); + } + *(typelib_TypeDescriptionReference **)uno_data = td.get()->pWeakRef; + break; + } + case typelib_TypeClass_ANY: + { + JLocalAutoRef jo_out_holder( jni ); + if (out_param) + { + jo_out_holder.reset( + jni->GetObjectArrayElement( (jobjectArray) java_data.l, 0 ) ); + jni.ensure_no_exception(); + java_data.l = jo_out_holder.get(); + } + + uno_Any * pAny = (uno_Any *)uno_data; + if (0 == java_data.l) // null-ref maps to XInterface null-ref + { + if (assign) + uno_any_destruct( pAny, 0 ); + uno_any_construct( + pAny, 0, m_jni_info->m_XInterface_type_info->m_td.get(), 0 ); + break; + } + + JLocalAutoRef jo_type( jni ); + JLocalAutoRef jo_wrapped_holder( jni ); + + if (JNI_FALSE != jni->IsInstanceOf( + java_data.l, m_jni_info->m_class_Any )) + { + // boxed any + jo_type.reset( jni->GetObjectField( + java_data.l, m_jni_info->m_field_Any__type ) ); + if (! jo_type.is()) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("] no type set at " + "com.sun.star.uno.Any!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + // wrapped value + jo_wrapped_holder.reset( + jni->GetObjectField( + java_data.l, m_jni_info->m_field_Any__object ) ); + java_data.l = jo_wrapped_holder.get(); + } + else + { + // create type out of class + JLocalAutoRef jo_class( jni, jni->GetObjectClass( java_data.l ) ); + jo_type.reset( create_type( jni, (jclass) jo_class.get() ) ); +#if OSL_DEBUG_LEVEL > 1 + { + JLocalAutoRef jo_toString( + jni, jni->CallObjectMethodA( + java_data.l, m_jni_info->m_method_Object_toString, 0 ) ); + jni.ensure_no_exception(); + OUString toString( + jstring_to_oustring( jni, (jstring) jo_toString.get() ) ); + } +#endif + } + + // get type name + JLocalAutoRef jo_type_name( + jni, jni->GetObjectField( + jo_type.get(), m_jni_info->m_field_Type__typeName ) ); + jni.ensure_no_exception(); + OUString type_name( + jstring_to_oustring( jni, (jstring) jo_type_name.get() ) ); + + ::com::sun::star::uno::TypeDescription value_td( type_name ); + if (! value_td.is()) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("] UNO type not found: ") ); + buf.append( type_name ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + typelib_TypeClass type_class = value_td.get()->eTypeClass; + + if (assign) + { + uno_any_destruct( pAny, 0 ); + } + try + { + switch (type_class) + { + case typelib_TypeClass_VOID: + pAny->pData = &pAny->pReserved; + break; + case typelib_TypeClass_CHAR: + pAny->pData = &pAny->pReserved; + *(jchar *) pAny->pData = jni->CallCharMethodA( + java_data.l, m_jni_info->m_method_Character_charValue, 0 ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_BOOLEAN: + pAny->pData = &pAny->pReserved; + *(jboolean *) pAny->pData = jni->CallBooleanMethodA( + java_data.l, m_jni_info->m_method_Boolean_booleanValue, 0 ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_BYTE: + pAny->pData = &pAny->pReserved; + *(jbyte *) pAny->pData = jni->CallByteMethodA( + java_data.l, m_jni_info->m_method_Byte_byteValue, 0 ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + pAny->pData = &pAny->pReserved; + *(jshort *) pAny->pData = jni->CallShortMethodA( + java_data.l, m_jni_info->m_method_Short_shortValue, 0 ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + pAny->pData = &pAny->pReserved; + *(jint *) pAny->pData = jni->CallIntMethodA( + java_data.l, m_jni_info->m_method_Integer_intValue, 0 ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (sizeof (sal_Int64) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(jlong *) pAny->pData = jni->CallLongMethodA( + java_data.l, m_jni_info->m_method_Long_longValue, 0 ); + jni.ensure_no_exception(); + } + else + { + auto_ptr< rtl_mem > mem( + rtl_mem::allocate( sizeof (sal_Int64) ) ); + *(jlong *) mem.get() = jni->CallLongMethodA( + java_data.l, m_jni_info->m_method_Long_longValue, 0 ); + jni.ensure_no_exception(); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_FLOAT: + if (sizeof (float) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(jfloat *) pAny->pData = jni->CallFloatMethodA( + java_data.l, m_jni_info->m_method_Float_floatValue, 0 ); + jni.ensure_no_exception(); + } + else + { + auto_ptr< rtl_mem > mem( + rtl_mem::allocate( sizeof (float) ) ); + *(jfloat *) mem.get() = jni->CallFloatMethodA( + java_data.l, m_jni_info->m_method_Float_floatValue, 0 ); + jni.ensure_no_exception(); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_DOUBLE: + if (sizeof (double) <= sizeof (void *)) + { + pAny->pData = &pAny->pReserved; + *(jdouble *) pAny->pData = + jni->CallDoubleMethodA( + java_data.l, + m_jni_info->m_method_Double_doubleValue, 0 ); + jni.ensure_no_exception(); + } + else + { + auto_ptr< rtl_mem > mem( + rtl_mem::allocate( sizeof (double) ) ); + *(jdouble *) mem.get() = + jni->CallDoubleMethodA( + java_data.l, + m_jni_info->m_method_Double_doubleValue, 0 ); + jni.ensure_no_exception(); + pAny->pData = mem.release(); + } + break; + case typelib_TypeClass_STRING: + // opt: anies often contain strings; copy string directly + pAny->pReserved = 0; + pAny->pData = &pAny->pReserved; + jstring_to_ustring( + jni, (rtl_uString **)pAny->pData, + (jstring) java_data.l ); + break; + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ENUM: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_INTERFACE: + pAny->pData = &pAny->pReserved; + map_to_uno( + jni, pAny->pData, java_data, + value_td.get()->pWeakRef, 0, + false /* no assign */, false /* no out param */ ); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + auto_ptr< rtl_mem > mem( + rtl_mem::allocate( value_td.get()->nSize ) ); + map_to_uno( + jni, mem.get(), java_data, value_td.get()->pWeakRef, 0, + false /* no assign */, false /* no out param */ ); + pAny->pData = mem.release(); + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( type_name ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("] unsupported value type " + "of any!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + } + catch (...) + { + if (assign) + { + // restore to valid any + uno_any_construct( pAny, 0, 0, 0 ); + } + throw; + } + typelib_typedescriptionreference_acquire( value_td.get()->pWeakRef ); + pAny->pType = value_td.get()->pWeakRef; + break; + } + case typelib_TypeClass_ENUM: + { + JLocalAutoRef jo_out_holder( jni ); + if (out_param) + { + jo_out_holder.reset( + jni->GetObjectArrayElement( (jobjectArray) java_data.l, 0 ) ); + jni.ensure_no_exception(); + java_data.l = jo_out_holder.get(); + } + if (0 == java_data.l) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] null-ref given!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + + *(jint *) uno_data = jni->GetIntField( + java_data.l, m_jni_info->m_field_Enum_m_value ); + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + JLocalAutoRef jo_out_holder( jni ); + if (out_param) + { + jo_out_holder.reset( + jni->GetObjectArrayElement( (jobjectArray) java_data.l, 0 ) ); + jni.ensure_no_exception(); + java_data.l = jo_out_holder.get(); + } + if (0 == java_data.l) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] null-ref given!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + + if (0 == info) + info = m_jni_info->get_type_info( jni, type ); + JNI_compound_type_info const * comp_info = + static_cast< JNI_compound_type_info const * >( info ); + + typelib_CompoundTypeDescription * comp_td = + (typelib_CompoundTypeDescription *)comp_info->m_td.get(); + bool polymorphic + = comp_td->aBase.eTypeClass == typelib_TypeClass_STRUCT + && reinterpret_cast< typelib_StructTypeDescription * >( + comp_td)->pParameterizedTypes != 0; + + sal_Int32 nPos = 0; + sal_Int32 nMembers = comp_td->nMembers; + try + { + if (0 != comp_td->pBaseTypeDescription) + { + map_to_uno( + jni, uno_data, java_data, + ((typelib_TypeDescription *) comp_td->pBaseTypeDescription) + ->pWeakRef, + comp_info->m_base, + assign, false /* no out param */ ); + } + + for ( ; nPos < nMembers; ++nPos ) + { + void * p = (char *)uno_data + comp_td->pMemberOffsets[ nPos ]; + typelib_TypeDescriptionReference * member_type = + comp_td->ppTypeRefs[ nPos ]; + jfieldID field_id = comp_info->m_fields[ nPos ]; + bool parameterizedType = polymorphic + && reinterpret_cast< typelib_StructTypeDescription * >( + comp_td)->pParameterizedTypes[nPos]; + switch (member_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + if (parameterizedType) { + JLocalAutoRef jo( + jni, jni->GetObjectField( java_data.l, field_id ) ); + if ( jo.get() == 0 ) { + *(jchar *) p = 0; + } else { + jvalue val; + val.l = jo.get(); + map_to_uno( + jni, p, val, member_type, 0, assign, false, + true ); + } + } else { + *(jchar *) p = jni->GetCharField( + java_data.l, field_id ); + } + break; + case typelib_TypeClass_BOOLEAN: + if (parameterizedType) { + JLocalAutoRef jo( + jni, jni->GetObjectField( java_data.l, field_id ) ); + if ( jo.get() == 0 ) { + *(jboolean *) p = false; + } else { + jvalue val; + val.l = jo.get(); + map_to_uno( + jni, p, val, member_type, 0, assign, false, + true ); + } + } else { + *(jboolean *) p = jni->GetBooleanField( + java_data.l, field_id ); + } + break; + case typelib_TypeClass_BYTE: + if (parameterizedType) { + JLocalAutoRef jo( + jni, jni->GetObjectField( java_data.l, field_id ) ); + if ( jo.get() == 0 ) { + *(jbyte *) p = 0; + } else { + jvalue val; + val.l = jo.get(); + map_to_uno( + jni, p, val, member_type, 0, assign, false, + true ); + } + } else { + *(jbyte *) p = jni->GetByteField( + java_data.l, field_id ); + } + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + if (parameterizedType) { + JLocalAutoRef jo( + jni, jni->GetObjectField( java_data.l, field_id ) ); + if ( jo.get() == 0 ) { + *(jshort *) p = 0; + } else { + jvalue val; + val.l = jo.get(); + map_to_uno( + jni, p, val, member_type, 0, assign, false, + true ); + } + } else { + *(jshort *) p = jni->GetShortField( + java_data.l, field_id ); + } + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + if (parameterizedType) { + JLocalAutoRef jo( + jni, jni->GetObjectField( java_data.l, field_id ) ); + if ( jo.get() == 0 ) { + *(jint *) p = 0; + } else { + jvalue val; + val.l = jo.get(); + map_to_uno( + jni, p, val, member_type, 0, assign, false, + true ); + } + } else { + *(jint *) p = jni->GetIntField( java_data.l, field_id ); + } + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (parameterizedType) { + JLocalAutoRef jo( + jni, jni->GetObjectField( java_data.l, field_id ) ); + if ( jo.get() == 0 ) { + *(jlong *) p = 0; + } else { + jvalue val; + val.l = jo.get(); + map_to_uno( + jni, p, val, member_type, 0, assign, false, + true ); + } + } else { + *(jlong *) p = jni->GetLongField( + java_data.l, field_id ); + } + break; + case typelib_TypeClass_FLOAT: + if (parameterizedType) { + JLocalAutoRef jo( + jni, jni->GetObjectField( java_data.l, field_id ) ); + if ( jo.get() == 0 ) { + *(jfloat *) p = 0; + } else { + jvalue val; + val.l = jo.get(); + map_to_uno( + jni, p, val, member_type, 0, assign, false, + true ); + } + } else { + *(jfloat *) p = jni->GetFloatField( + java_data.l, field_id ); + } + break; + case typelib_TypeClass_DOUBLE: + if (parameterizedType) { + JLocalAutoRef jo( + jni, jni->GetObjectField( java_data.l, field_id ) ); + if ( jo.get() == 0 ) { + *(jdouble *) p = 0; + } else { + jvalue val; + val.l = jo.get(); + map_to_uno( + jni, p, val, member_type, 0, assign, false, + true ); + } + } else { + *(jdouble *) p = jni->GetDoubleField( + java_data.l, field_id ); + } + break; + default: + { + JLocalAutoRef jo_field( jni ); + bool checkNull; + if (0 == field_id) + { + // special for Message: call Throwable.getMessage() + OSL_ASSERT( + type_equals( + type, + m_jni_info->m_Exception_type.getTypeLibType() ) + || type_equals( + type, + m_jni_info->m_RuntimeException_type. + getTypeLibType() ) ); + OSL_ASSERT( 0 == nPos ); // first member + // call getMessage() + jo_field.reset( + jni->CallObjectMethodA( + java_data.l, + m_jni_info->m_method_Throwable_getMessage, 0 ) + ); + jni.ensure_no_exception(); + checkNull = true; + } + else + { + jo_field.reset( + jni->GetObjectField( java_data.l, field_id ) ); + checkNull = parameterizedType; + } + if (checkNull && !jo_field.is()) { + createDefaultUnoValue(jni, p, member_type, 0, assign); + } else { + jvalue val; + val.l = jo_field.get(); + map_to_uno( + jni, p, val, member_type, 0, + assign, false /* no out param */ ); + } + break; + } + } + } + } + catch (...) + { + if (! assign) + { + // cleanup + for ( sal_Int32 nCleanup = 0; nCleanup < nPos; ++nCleanup ) + { + void * p = + (char *)uno_data + comp_td->pMemberOffsets[ nCleanup ]; + uno_type_destructData( + p, comp_td->ppTypeRefs[ nCleanup ], 0 ); + } + if (0 != comp_td->pBaseTypeDescription) + { + uno_destructData( + uno_data, + (typelib_TypeDescription *) comp_td + ->pBaseTypeDescription, 0 ); + } + } + throw; + } + break; + } + case typelib_TypeClass_SEQUENCE: + { + JLocalAutoRef jo_out_holder( jni ); + if (out_param) + { + jo_out_holder.reset( + jni->GetObjectArrayElement( (jobjectArray) java_data.l, 0 ) ); + jni.ensure_no_exception(); + java_data.l = jo_out_holder.get(); + } + if (0 == java_data.l) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] null-ref given!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + + TypeDescr td( type ); + typelib_TypeDescriptionReference * element_type = + ((typelib_IndirectTypeDescription *)td.get())->pType; + + auto_ptr< rtl_mem > seq; + sal_Int32 nElements = jni->GetArrayLength( (jarray) java_data.l ); + + switch (element_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + seq.reset( seq_allocate( nElements, sizeof (sal_Unicode) ) ); + jni->GetCharArrayRegion( + (jcharArray) java_data.l, 0, nElements, + (jchar *) ((uno_Sequence *) seq.get())->elements ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_BOOLEAN: + seq.reset( seq_allocate( nElements, sizeof (sal_Bool) ) ); + jni->GetBooleanArrayRegion( + (jbooleanArray) java_data.l, 0, nElements, + (jboolean *) ((uno_Sequence *) seq.get())->elements ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_BYTE: + seq.reset( seq_allocate( nElements, sizeof (sal_Int8) ) ); + jni->GetByteArrayRegion( + (jbyteArray) java_data.l, 0, nElements, + (jbyte *) ((uno_Sequence *) seq.get())->elements ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + seq.reset( seq_allocate( nElements, sizeof (sal_Int16) ) ); + jni->GetShortArrayRegion( + (jshortArray) java_data.l, 0, nElements, + (jshort *) ((uno_Sequence *) seq.get())->elements ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + seq.reset( seq_allocate( nElements, sizeof (sal_Int32) ) ); + jni->GetIntArrayRegion( + (jintArray) java_data.l, 0, nElements, + (jint *) ((uno_Sequence *) seq.get())->elements ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + seq.reset( seq_allocate( nElements, sizeof (sal_Int64) ) ); + jni->GetLongArrayRegion( + (jlongArray) java_data.l, 0, nElements, + (jlong *) ((uno_Sequence *) seq.get())->elements ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_FLOAT: + seq.reset( seq_allocate( nElements, sizeof (float) ) ); + jni->GetFloatArrayRegion( + (jfloatArray) java_data.l, 0, nElements, + (jfloat *)((uno_Sequence *)seq.get())->elements ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_DOUBLE: + seq.reset( seq_allocate( nElements, sizeof (double) ) ); + jni->GetDoubleArrayRegion( + (jdoubleArray) java_data.l, 0, nElements, + (jdouble *) ((uno_Sequence *) seq.get())->elements ); + jni.ensure_no_exception(); + break; + case typelib_TypeClass_STRING: + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + case typelib_TypeClass_ENUM: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_INTERFACE: + { + TypeDescr element_td( element_type ); + seq.reset( seq_allocate( nElements, element_td.get()->nSize ) ); + + JNI_type_info const * element_info; + if (typelib_TypeClass_STRUCT == element_type->eTypeClass || + typelib_TypeClass_EXCEPTION == element_type->eTypeClass || + typelib_TypeClass_INTERFACE == element_type->eTypeClass) + { + element_info = + m_jni_info->get_type_info( jni, element_td.get() ); + } + else + { + element_info = 0; + } + + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + try + { + JLocalAutoRef jo( + jni, jni->GetObjectArrayElement( + (jobjectArray) java_data.l, nPos ) ); + jni.ensure_no_exception(); + jvalue val; + val.l = jo.get(); + void * p = + ((uno_Sequence *)seq.get())->elements + + (nPos * element_td.get()->nSize); + map_to_uno( + jni, p, val, element_td.get()->pWeakRef, element_info, + false /* no assign */, false /* no out param */ ); + } + catch (...) + { + // cleanup + for ( sal_Int32 nCleanPos = 0; + nCleanPos < nPos; ++nCleanPos ) + { + void * p = + ((uno_Sequence *)seq.get())->elements + + (nCleanPos * element_td.get()->nSize); + uno_destructData( p, element_td.get(), 0 ); + } + throw; + } + } + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("] unsupported sequence element" + " type: ") ); + buf.append( OUString::unacquired( &element_type->pTypeName ) ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + + if (assign) + uno_destructData( uno_data, td.get(), 0 ); + *(uno_Sequence **)uno_data = (uno_Sequence *)seq.release(); + break; + } + case typelib_TypeClass_INTERFACE: + { + JLocalAutoRef jo_out_holder( jni ); + if (out_param) + { + jo_out_holder.reset( + jni->GetObjectArrayElement( (jobjectArray) java_data.l, 0 ) ); + jni.ensure_no_exception(); + java_data.l = jo_out_holder.get(); + } + + if (0 == java_data.l) // null-ref + { + if (assign) + { + uno_Interface * p = *(uno_Interface **)uno_data; + if (0 != p) + (*p->release)( p ); + } + *(uno_Interface **)uno_data = 0; + } + else + { + if (0 == info) + info = m_jni_info->get_type_info( jni, type ); + JNI_interface_type_info const * iface_info = + static_cast< JNI_interface_type_info const * >( info ); + uno_Interface * pUnoI = map_to_uno( jni, java_data.l, iface_info ); + if (assign) + { + uno_Interface * p = *(uno_Interface **)uno_data; + if (0 != p) + (*p->release)( p ); + } + *(uno_Interface **)uno_data = pUnoI; + } + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_uno():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported type!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } +} + +//############################################################################## + +//______________________________________________________________________________ +void Bridge::map_to_java( + JNI_context const & jni, + jvalue * java_data, void const * uno_data, + typelib_TypeDescriptionReference * type, + JNI_type_info const * info /* maybe 0 */, + bool in_param, bool out_param, + bool special_wrapped_integral_types ) const +{ + switch (type->eTypeClass) + { + case typelib_TypeClass_CHAR: + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_ar( jni, jni->NewCharArray( 1 ) ); + jni.ensure_no_exception(); + if (in_param) + { + jni->SetCharArrayRegion( + (jcharArray) jo_ar.get(), 0, 1, (jchar *) uno_data ); + jni.ensure_no_exception(); + } + java_data->l = jo_ar.release(); + } + else + { + if (in_param) + { + jni->SetCharArrayRegion( + (jcharArray) java_data->l, 0, 1, (jchar *) uno_data ); + jni.ensure_no_exception(); + } + } + } + else if (special_wrapped_integral_types) + { + jvalue arg; + arg.c = *(jchar const *) uno_data; + java_data->l = jni->NewObjectA( + m_jni_info->m_class_Character, + m_jni_info->m_ctor_Character_with_char, &arg ); + jni.ensure_no_exception(); + } + else + { + java_data->c = *(jchar const *) uno_data; + } + break; + case typelib_TypeClass_BOOLEAN: + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_ar( jni, jni->NewBooleanArray( 1 ) ); + jni.ensure_no_exception(); + if (in_param) + { + jni->SetBooleanArrayRegion( + (jbooleanArray) jo_ar.get(), + 0, 1, (jboolean *) uno_data ); + jni.ensure_no_exception(); + } + java_data->l = jo_ar.release(); + } + else + { + if (in_param) + { + jni->SetBooleanArrayRegion( + (jbooleanArray) java_data->l, + 0, 1, (jboolean *) uno_data ); + jni.ensure_no_exception(); + } + } + } + else if (special_wrapped_integral_types) + { + jvalue arg; + arg.z = *(jboolean const *) uno_data; + java_data->l = jni->NewObjectA( + m_jni_info->m_class_Boolean, + m_jni_info->m_ctor_Boolean_with_boolean, &arg ); + jni.ensure_no_exception(); + } + else + { + java_data->z = *(jboolean const *) uno_data; + } + break; + case typelib_TypeClass_BYTE: + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_ar( jni, jni->NewByteArray( 1 ) ); + jni.ensure_no_exception(); + if (in_param) + { + jni->SetByteArrayRegion( + (jbyteArray) jo_ar.get(), 0, 1, (jbyte *) uno_data ); + jni.ensure_no_exception(); + } + java_data->l = jo_ar.release(); + } + else + { + if (in_param) + { + jni->SetByteArrayRegion( + (jbyteArray) java_data->l, 0, 1, (jbyte *) uno_data ); + jni.ensure_no_exception(); + } + } + } + else if (special_wrapped_integral_types) + { + jvalue arg; + arg.b = *(jbyte const *) uno_data; + java_data->l = jni->NewObjectA( + m_jni_info->m_class_Byte, + m_jni_info->m_ctor_Byte_with_byte, &arg ); + jni.ensure_no_exception(); + } + else + { + java_data->b = *(jbyte const *) uno_data; + } + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_ar( jni, jni->NewShortArray( 1 ) ); + jni.ensure_no_exception(); + if (in_param) + { + jni->SetShortArrayRegion( + (jshortArray) jo_ar.get(), 0, 1, (jshort *) uno_data ); + jni.ensure_no_exception(); + } + java_data->l = jo_ar.release(); + } + else + { + if (in_param) + { + jni->SetShortArrayRegion( + (jshortArray) java_data->l, 0, 1, (jshort *) uno_data ); + jni.ensure_no_exception(); + } + } + } + else if (special_wrapped_integral_types) + { + jvalue arg; + arg.s = *(jshort const *) uno_data; + java_data->l = jni->NewObjectA( + m_jni_info->m_class_Short, + m_jni_info->m_ctor_Short_with_short, &arg ); + jni.ensure_no_exception(); + } + else + { + java_data->s = *(jshort const *) uno_data; + } + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_ar( jni, jni->NewIntArray( 1 ) ); + jni.ensure_no_exception(); + if (in_param) + { + jni->SetIntArrayRegion( + (jintArray) jo_ar.get(), 0, 1, (jint *) uno_data ); + jni.ensure_no_exception(); + } + java_data->l = jo_ar.release(); + } + else + { + if (in_param) + { + jni->SetIntArrayRegion( + (jintArray) java_data->l, 0, 1, (jint *) uno_data ); + jni.ensure_no_exception(); + } + } + } + else if (special_wrapped_integral_types) + { + jvalue arg; + arg.i = *(jint const *) uno_data; + java_data->l = jni->NewObjectA( + m_jni_info->m_class_Integer, + m_jni_info->m_ctor_Integer_with_int, &arg ); + jni.ensure_no_exception(); + } + else + { + java_data->i = *(jint const *) uno_data; + } + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_ar( jni, jni->NewLongArray( 1 ) ); + jni.ensure_no_exception(); + if (in_param) + { + jni->SetLongArrayRegion( + (jlongArray)jo_ar.get(), 0, 1, (jlong *) uno_data ); + jni.ensure_no_exception(); + } + java_data->l = jo_ar.release(); + } + else + { + if (in_param) + { + jni->SetLongArrayRegion( + (jlongArray)java_data->l, 0, 1, (jlong *) uno_data ); + jni.ensure_no_exception(); + } + } + } + else if (special_wrapped_integral_types) + { + jvalue arg; + arg.j = *(jlong const *) uno_data; + java_data->l = jni->NewObjectA( + m_jni_info->m_class_Long, + m_jni_info->m_ctor_Long_with_long, &arg ); + jni.ensure_no_exception(); + } + else + { + java_data->j = *(jlong const *) uno_data; + } + break; + case typelib_TypeClass_FLOAT: + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_ar( jni, jni->NewFloatArray( 1 ) ); + jni.ensure_no_exception(); + if (in_param) + { + jni->SetFloatArrayRegion( + (jfloatArray) jo_ar.get(), 0, 1, (jfloat *) uno_data ); + jni.ensure_no_exception(); + } + java_data->l = jo_ar.release(); + } + else + { + if (in_param) + { + jni->SetFloatArrayRegion( + (jfloatArray) java_data->l, 0, 1, (jfloat *) uno_data ); + jni.ensure_no_exception(); + } + } + } + else if (special_wrapped_integral_types) + { + jvalue arg; + arg.f = *(jfloat const *) uno_data; + java_data->l = jni->NewObjectA( + m_jni_info->m_class_Float, + m_jni_info->m_ctor_Float_with_float, &arg ); + jni.ensure_no_exception(); + } + else + { + java_data->f = *(jfloat const *) uno_data; + } + break; + case typelib_TypeClass_DOUBLE: + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_ar( jni, jni->NewDoubleArray( 1 ) ); + jni.ensure_no_exception(); + if (in_param) + { + jni->SetDoubleArrayRegion( + (jdoubleArray) jo_ar.get(), + 0, 1, (jdouble *) uno_data ); + jni.ensure_no_exception(); + } + java_data->l = jo_ar.release(); + } + else + { + if (in_param) + { + jni->SetDoubleArrayRegion( + (jdoubleArray) java_data->l, + 0, 1, (jdouble *) uno_data ); + jni.ensure_no_exception(); + } + } + } + else if (special_wrapped_integral_types) + { + jvalue arg; + arg.d = *(double const *)uno_data; + java_data->l = jni->NewObjectA( + m_jni_info->m_class_Double, + m_jni_info->m_ctor_Double_with_double, &arg ); + jni.ensure_no_exception(); + } + else + { + java_data->d = *(jdouble const *) uno_data; + } + break; + case typelib_TypeClass_STRING: + { + if (out_param) + { + JLocalAutoRef jo_in( jni ); + if (in_param) + { + jo_in.reset( + ustring_to_jstring( + jni, *(rtl_uString * const *) uno_data ) ); + } + if (0 == java_data->l) + { + java_data->l = jni->NewObjectArray( + 1, m_jni_info->m_class_String, jo_in.get() ); + jni.ensure_no_exception(); + } + else + { + jni->SetObjectArrayElement( + (jobjectArray) java_data->l, 0, jo_in.get() ); + jni.ensure_no_exception(); + } + } + else + { + OSL_ASSERT( in_param ); + java_data->l = + ustring_to_jstring( jni, *(rtl_uString * const *) uno_data ); + } + break; + } + case typelib_TypeClass_TYPE: + { + if (out_param) + { + JLocalAutoRef jo_in( jni ); + if (in_param) + { + jo_in.reset( + create_type( + jni, + *(typelib_TypeDescriptionReference * const *) uno_data ) + ); + } + if (0 == java_data->l) + { + java_data->l = jni->NewObjectArray( + 1, m_jni_info->m_class_Type, jo_in.get() ); + jni.ensure_no_exception(); + } + else + { + jni->SetObjectArrayElement( + (jobjectArray) java_data->l, 0, jo_in.get() ); + jni.ensure_no_exception(); + } + } + else + { + OSL_ASSERT( in_param ); + java_data->l = + create_type( + jni, + *(typelib_TypeDescriptionReference * const *) uno_data ); + } + break; + } + case typelib_TypeClass_ANY: + { + JLocalAutoRef jo_any( jni ); + if (in_param) + { + uno_Any const * pAny = (uno_Any const *)uno_data; + +#if defined BRIDGES_JNI_UNO_FORCE_BOXED_ANY + if (typelib_TypeClass_VOID == pAny->pType->eTypeClass) + { + jo_any.reset( + jni->NewLocalRef( m_jni_info->m_object_Any_VOID ) ); + } + else + { + jvalue args[ 2 ]; + map_to_java( + jni, &args[ 1 ], pAny->pData, pAny->pType, 0, + true /* in */, false /* no out */, + true /* create integral wrappers */ ); + jo_any.reset( args[ 1 ].l ); + // build up com.sun.star.uno.Any + JLocalAutoRef jo_type( jni, create_type( jni, pAny->pType ) ); + args[ 0 ].l = jo_type.get(); + jo_any.reset( + jni->NewObjectA( + m_jni_info->m_class_Any, + m_jni_info->m_ctor_Any_with_Type_Object, args ) ); + jni.ensure_no_exception(); + } +#else + switch (pAny->pType->eTypeClass) + { + case typelib_TypeClass_VOID: + jo_any.reset( + jni->NewLocalRef( m_jni_info->m_object_Any_VOID ) ); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + { + jvalue args[ 2 ]; + args[ 0 ].s = *(jshort const *) pAny->pData; + JLocalAutoRef jo_val( + jni, jni->NewObjectA( + m_jni_info->m_class_Short, + m_jni_info->m_ctor_Short_with_short, args ) ); + jni.ensure_no_exception(); + // box up in com.sun.star.uno.Any + args[ 0 ].l = m_jni_info->m_object_Type_UNSIGNED_SHORT; + args[ 1 ].l = jo_val.get(); + jo_any.reset( + jni->NewObjectA( + m_jni_info->m_class_Any, + m_jni_info->m_ctor_Any_with_Type_Object, args ) ); + jni.ensure_no_exception(); + break; + } + case typelib_TypeClass_UNSIGNED_LONG: + { + jvalue args[ 2 ]; + args[ 0 ].i = *(jint const *) pAny->pData; + JLocalAutoRef jo_val( + jni, jni->NewObjectA( + m_jni_info->m_class_Integer, + m_jni_info->m_ctor_Integer_with_int, args ) ); + jni.ensure_no_exception(); + // box up in com.sun.star.uno.Any + args[ 0 ].l = m_jni_info->m_object_Type_UNSIGNED_LONG; + args[ 1 ].l = jo_val.get(); + jo_any.reset( + jni->NewObjectA( + m_jni_info->m_class_Any, + m_jni_info->m_ctor_Any_with_Type_Object, args ) ); + jni.ensure_no_exception(); + break; + } + case typelib_TypeClass_UNSIGNED_HYPER: + { + jvalue args[ 2 ]; + args[ 0 ].j = *(jlong const *) pAny->pData; + JLocalAutoRef jo_val( + jni, jni->NewObjectA( + m_jni_info->m_class_Long, + m_jni_info->m_ctor_Long_with_long, args ) ); + jni.ensure_no_exception(); + // box up in com.sun.star.uno.Any + args[ 0 ].l = m_jni_info->m_object_Type_UNSIGNED_HYPER; + args[ 1 ].l = jo_val.get(); + jo_any.reset( + jni->NewObjectA( + m_jni_info->m_class_Any, + m_jni_info->m_ctor_Any_with_Type_Object, args ) ); + jni.ensure_no_exception(); + break; + } + case typelib_TypeClass_STRING: // opt strings + jo_any.reset( ustring_to_jstring( + jni, (rtl_uString *) pAny->pReserved ) ); + break; + case typelib_TypeClass_SEQUENCE: + { + jvalue java_data2; + // prefetch sequence td + TypeDescr seq_td( pAny->pType ); + map_to_java( + jni, &java_data2, pAny->pData, seq_td.get()->pWeakRef, 0, + true /* in */, false /* no out */, + true /* create integral wrappers */ ); + jo_any.reset( java_data2.l ); + + // determine inner element type + ::com::sun::star::uno::Type element_type( + ((typelib_IndirectTypeDescription *)seq_td.get())->pType ); + while (typelib_TypeClass_SEQUENCE == + element_type.getTypeLibType()->eTypeClass) + { + TypeDescr element_td( element_type.getTypeLibType() ); + typelib_typedescriptionreference_assign( + reinterpret_cast< typelib_TypeDescriptionReference ** >( + &element_type ), + ((typelib_IndirectTypeDescription *)element_td.get()) + ->pType ); + } + // box up only if unsigned element type + switch (element_type.getTypeLibType()->eTypeClass) + { + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_UNSIGNED_HYPER: + { + jvalue args[ 2 ]; + JLocalAutoRef jo_type( + jni, create_type( jni, seq_td.get()->pWeakRef ) ); + args[ 0 ].l = jo_type.get(); + args[ 1 ].l = jo_any.get(); + jo_any.reset( + jni->NewObjectA( + m_jni_info->m_class_Any, + m_jni_info->m_ctor_Any_with_Type_Object, args ) ); + jni.ensure_no_exception(); + break; + } + default: + break; + } + break; + } + case typelib_TypeClass_INTERFACE: + { + uno_Interface * pUnoI = (uno_Interface *)pAny->pReserved; + if (is_XInterface( pAny->pType )) + { + if (0 != pUnoI) + { + jo_any.reset( + map_to_java( + jni, pUnoI, + m_jni_info->m_XInterface_type_info ) ); + } + // else: empty XInterface ref maps to null-ref + } + else + { + JNI_interface_type_info const * iface_info = + static_cast< JNI_interface_type_info const * >( + m_jni_info->get_type_info( jni, pAny->pType ) ); + if (0 != pUnoI) + { + jo_any.reset( map_to_java( jni, pUnoI, iface_info ) ); + } + // box up in com.sun.star.uno.Any + jvalue args[ 2 ]; + args[ 0 ].l = iface_info->m_type; + args[ 1 ].l = jo_any.get(); + jo_any.reset( + jni->NewObjectA( + m_jni_info->m_class_Any, + m_jni_info->m_ctor_Any_with_Type_Object, args ) ); + jni.ensure_no_exception(); + } + break; + } + case typelib_TypeClass_STRUCT: + { + // Do not lose information about type arguments of instantiated + // polymorphic struct types: + rtl::OUString const & name = rtl::OUString::unacquired( + &pAny->pType->pTypeName); + OSL_ASSERT(name.getLength() > 0); + if (name[name.getLength() - 1] == '>') + { + // Box up in com.sun.star.uno.Any: + JLocalAutoRef jo_type(jni, create_type(jni, pAny->pType)); + jvalue java_data2; + map_to_java( + jni, &java_data2, pAny->pData, pAny->pType, 0, true, + false); + jo_any.reset(java_data2.l); + jvalue args[2]; + args[0].l = jo_type.get(); + args[1].l = jo_any.get(); + jo_any.reset( + jni->NewObjectA( + m_jni_info->m_class_Any, + m_jni_info->m_ctor_Any_with_Type_Object, args)); + jni.ensure_no_exception(); + break; + } + // fall through + } + default: + { + jvalue java_data2; + map_to_java( + jni, &java_data2, pAny->pData, pAny->pType, 0, + true /* in */, false /* no out */, + true /* create integral wrappers */ ); + jo_any.reset( java_data2.l ); + break; + } + } +#endif + } + + if (out_param) + { + if (0 == java_data->l) + { + java_data->l = jni->NewObjectArray( + 1, m_jni_info->m_class_Object, jo_any.get() ); + jni.ensure_no_exception(); + } + else + { + jni->SetObjectArrayElement( + (jobjectArray) java_data->l, 0, jo_any.get() ); + jni.ensure_no_exception(); + } + } + else + { + java_data->l = jo_any.release(); + } + break; + } + case typelib_TypeClass_ENUM: + { + OUString const & type_name = OUString::unacquired( &type->pTypeName ); + OString class_name( + OUStringToOString( type_name, RTL_TEXTENCODING_JAVA_UTF8 ) ); + JLocalAutoRef jo_enum_class( + jni, find_class( jni, class_name.getStr() ) ); + + JLocalAutoRef jo_enum( jni ); + if (in_param) + { + // call static <enum_class>.fromInt( int ) + OStringBuffer sig_buf( 5 + class_name.getLength() ); + sig_buf.append( RTL_CONSTASCII_STRINGPARAM("(I)L") ); + sig_buf.append( class_name.replace( '.', '/' ) ); + sig_buf.append( ';' ); + OString sig( sig_buf.makeStringAndClear() ); + jmethodID method_id = jni->GetStaticMethodID( + (jclass) jo_enum_class.get(), "fromInt", sig.getStr() ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != method_id ); + + jvalue arg; + arg.i = *(jint const *) uno_data; + jo_enum.reset( + jni->CallStaticObjectMethodA( + (jclass) jo_enum_class.get(), method_id, &arg ) ); + jni.ensure_no_exception(); + } + if (out_param) + { + if (0 == java_data->l) + { + java_data->l = jni->NewObjectArray( + 1, (jclass) jo_enum_class.get(), jo_enum.get() ); + jni.ensure_no_exception(); + } + else + { + jni->SetObjectArrayElement( + (jobjectArray) java_data->l, 0, jo_enum.get() ); + jni.ensure_no_exception(); + } + } + else + { + java_data->l = jo_enum.release(); + } + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + if (0 == info) + info = m_jni_info->get_type_info( jni, type ); + JNI_compound_type_info const * comp_info = + static_cast< JNI_compound_type_info const * >( info ); + + JLocalAutoRef jo_comp( jni ); + if (in_param) + { + if (typelib_TypeClass_EXCEPTION == type->eTypeClass) + { + JLocalAutoRef jo_message( + jni, ustring_to_jstring( jni, *(rtl_uString **)uno_data ) ); + jvalue arg; + arg.l = jo_message.get(); + jo_comp.reset( + jni->NewObjectA( + comp_info->m_class, comp_info->m_exc_ctor, &arg ) ); + jni.ensure_no_exception(); + } + else + { + jo_comp.reset( jni->AllocObject( comp_info->m_class ) ); + jni.ensure_no_exception(); + } + + for ( JNI_compound_type_info const * linfo = comp_info; + 0 != linfo; + linfo = static_cast< JNI_compound_type_info const * >( + linfo->m_base ) ) + { + typelib_CompoundTypeDescription * comp_td = + (typelib_CompoundTypeDescription *)linfo->m_td.get(); + typelib_TypeDescriptionReference ** ppMemberTypeRefs = + comp_td->ppTypeRefs; + sal_Int32 * pMemberOffsets = comp_td->pMemberOffsets; + bool polymorphic + = comp_td->aBase.eTypeClass == typelib_TypeClass_STRUCT + && reinterpret_cast< typelib_StructTypeDescription * >( + comp_td)->pParameterizedTypes != 0; + for ( sal_Int32 nPos = comp_td->nMembers; nPos--; ) + { + jfieldID field_id = linfo->m_fields[ nPos ]; + if (0 != field_id) + { + void const * p = + (char const *)uno_data + pMemberOffsets[ nPos ]; + typelib_TypeDescriptionReference * member_type = + ppMemberTypeRefs[ nPos ]; + bool parameterizedType = polymorphic + && (reinterpret_cast< + typelib_StructTypeDescription * >(comp_td)-> + pParameterizedTypes[nPos]); + switch (member_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + if (parameterizedType) { + jvalue arg; + arg.c = *(jchar const *) p; + JLocalAutoRef jo( + jni, + jni->NewObjectA( + m_jni_info->m_class_Character, + m_jni_info->m_ctor_Character_with_char, + &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectField( + jo_comp.get(), field_id, jo.get() ); + } else { + jni->SetCharField( + jo_comp.get(), + field_id, *(jchar const *) p ); + } + break; + case typelib_TypeClass_BOOLEAN: + if (parameterizedType) { + jvalue arg; + arg.z = *(jboolean const *) p; + JLocalAutoRef jo( + jni, + jni->NewObjectA( + m_jni_info->m_class_Boolean, + m_jni_info->m_ctor_Boolean_with_boolean, + &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectField( + jo_comp.get(), field_id, jo.get() ); + } else { + jni->SetBooleanField( + jo_comp.get(), + field_id, *(jboolean const *) p ); + } + break; + case typelib_TypeClass_BYTE: + if (parameterizedType) { + jvalue arg; + arg.b = *(jbyte const *) p; + JLocalAutoRef jo( + jni, + jni->NewObjectA( + m_jni_info->m_class_Byte, + m_jni_info->m_ctor_Byte_with_byte, + &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectField( + jo_comp.get(), field_id, jo.get() ); + } else { + jni->SetByteField( + jo_comp.get(), + field_id, *(jbyte const *) p ); + } + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + if (parameterizedType) { + jvalue arg; + arg.s = *(jshort const *) p; + JLocalAutoRef jo( + jni, + jni->NewObjectA( + m_jni_info->m_class_Short, + m_jni_info->m_ctor_Short_with_short, + &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectField( + jo_comp.get(), field_id, jo.get() ); + } else { + jni->SetShortField( + jo_comp.get(), + field_id, *(jshort const *) p ); + } + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + if (parameterizedType) { + jvalue arg; + arg.i = *(jint const *) p; + JLocalAutoRef jo( + jni, + jni->NewObjectA( + m_jni_info->m_class_Integer, + m_jni_info->m_ctor_Integer_with_int, + &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectField( + jo_comp.get(), field_id, jo.get() ); + } else { + jni->SetIntField( + jo_comp.get(), + field_id, *(jint const *) p ); + } + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (parameterizedType) { + jvalue arg; + arg.j = *(jlong const *) p; + JLocalAutoRef jo( + jni, + jni->NewObjectA( + m_jni_info->m_class_Long, + m_jni_info->m_ctor_Long_with_long, + &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectField( + jo_comp.get(), field_id, jo.get() ); + } else { + jni->SetLongField( + jo_comp.get(), + field_id, *(jlong const *) p ); + } + break; + case typelib_TypeClass_FLOAT: + if (parameterizedType) { + jvalue arg; + arg.f = *(jfloat const *) p; + JLocalAutoRef jo( + jni, + jni->NewObjectA( + m_jni_info->m_class_Float, + m_jni_info->m_ctor_Float_with_float, + &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectField( + jo_comp.get(), field_id, jo.get() ); + } else { + jni->SetFloatField( + jo_comp.get(), + field_id, *(jfloat const *) p ); + } + break; + case typelib_TypeClass_DOUBLE: + if (parameterizedType) { + jvalue arg; + arg.d = *(jdouble const *) p; + JLocalAutoRef jo( + jni, + jni->NewObjectA( + m_jni_info->m_class_Double, + m_jni_info->m_ctor_Double_with_double, + &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectField( + jo_comp.get(), field_id, jo.get() ); + } else { + jni->SetDoubleField( + jo_comp.get(), + field_id, *(jdouble const *) p ); + } + break; + case typelib_TypeClass_STRING: // string opt here + { + JLocalAutoRef jo_string( + jni, ustring_to_jstring( + jni, *(rtl_uString * const *) p ) ); + jni->SetObjectField( + jo_comp.get(), field_id, jo_string.get() ); + break; + } + default: + { + jvalue java_data2; + map_to_java( + jni, &java_data2, p, member_type, 0, + true /* in */, false /* no out */ ); + JLocalAutoRef jo_obj( jni, java_data2.l ); + jni->SetObjectField( + jo_comp.get(), field_id, jo_obj.get() ); + break; + } + } + } + } + } + } + if (out_param) + { + if (0 == java_data->l) + { + java_data->l = + jni->NewObjectArray( 1, comp_info->m_class, jo_comp.get() ); + jni.ensure_no_exception(); + } + else + { + jni->SetObjectArrayElement( + (jobjectArray) java_data->l, 0, jo_comp.get() ); + jni.ensure_no_exception(); + } + } + else + { + java_data->l = jo_comp.release(); + } + break; + } + case typelib_TypeClass_SEQUENCE: + { + // xxx todo: possible opt for pure out sequences + JLocalAutoRef jo_ar( jni ); + + sal_Int32 nElements; + uno_Sequence const * seq = 0; + if (in_param) + { + seq = *(uno_Sequence * const *)uno_data; + nElements = seq->nElements; + } + else + { + nElements = 0; + } + + TypeDescr td( type ); + typelib_TypeDescriptionReference * element_type = + ((typelib_IndirectTypeDescription *)td.get())->pType; + + switch (element_type->eTypeClass) + { + case typelib_TypeClass_CHAR: + jo_ar.reset( jni->NewCharArray( nElements ) ); + jni.ensure_no_exception(); + if (0 < nElements) + { + jni->SetCharArrayRegion( + (jcharArray) jo_ar.get(), + 0, nElements, (jchar *) seq->elements ); + jni.ensure_no_exception(); + } + break; + case typelib_TypeClass_BOOLEAN: + jo_ar.reset( jni->NewBooleanArray( nElements ) ); + jni.ensure_no_exception(); + if (0 < nElements) + { + jni->SetBooleanArrayRegion( + (jbooleanArray) jo_ar.get(), + 0, nElements, (jboolean *) seq->elements ); + jni.ensure_no_exception(); + } + break; + case typelib_TypeClass_BYTE: + jo_ar.reset( jni->NewByteArray( nElements ) ); + jni.ensure_no_exception(); + if (0 < nElements) + { + jni->SetByteArrayRegion( + (jbyteArray) jo_ar.get(), + 0, nElements, (jbyte *) seq->elements ); + jni.ensure_no_exception(); + } + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + jo_ar.reset( jni->NewShortArray( nElements ) ); + jni.ensure_no_exception(); + if (0 < nElements) + { + jni->SetShortArrayRegion( + (jshortArray) jo_ar.get(), + 0, nElements, (jshort *) seq->elements ); + jni.ensure_no_exception(); + } + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + jo_ar.reset( jni->NewIntArray( nElements ) ); + jni.ensure_no_exception(); + if (0 < nElements) + { + jni->SetIntArrayRegion( + (jintArray) jo_ar.get(), + 0, nElements, (jint *) seq->elements ); + jni.ensure_no_exception(); + } + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + jo_ar.reset( jni->NewLongArray( nElements ) ); + jni.ensure_no_exception(); + if (0 < nElements) + { + jni->SetLongArrayRegion( + (jlongArray) jo_ar.get(), + 0, nElements, (jlong *) seq->elements ); + jni.ensure_no_exception(); + } + break; + case typelib_TypeClass_FLOAT: + jo_ar.reset( jni->NewFloatArray( nElements ) ); + jni.ensure_no_exception(); + if (0 < nElements) + { + jni->SetFloatArrayRegion( + (jfloatArray) jo_ar.get(), + 0, nElements, (jfloat *) seq->elements ); + jni.ensure_no_exception(); + } + break; + case typelib_TypeClass_DOUBLE: + jo_ar.reset( jni->NewDoubleArray( nElements ) ); + jni.ensure_no_exception(); + if (0 < nElements) + { + jni->SetDoubleArrayRegion( + (jdoubleArray) jo_ar.get(), + 0, nElements, (jdouble *) seq->elements ); + jni.ensure_no_exception(); + } + break; + case typelib_TypeClass_STRING: + jo_ar.reset( + jni->NewObjectArray( + nElements, m_jni_info->m_class_String, 0 ) ); + jni.ensure_no_exception(); + if (in_param) + { + rtl_uString * const * pp = + (rtl_uString * const *) seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + JLocalAutoRef jo_string( + jni, ustring_to_jstring( jni, pp[ nPos ] ) ); + jni->SetObjectArrayElement( + (jobjectArray) jo_ar.get(), nPos, jo_string.get() ); + jni.ensure_no_exception(); + } + } + break; + case typelib_TypeClass_TYPE: + jo_ar.reset( + jni->NewObjectArray( nElements, m_jni_info->m_class_Type, 0 ) ); + jni.ensure_no_exception(); + if (in_param) + { + typelib_TypeDescriptionReference * const * pp = + (typelib_TypeDescriptionReference * const *)seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + jvalue val; + map_to_java( + jni, &val, &pp[ nPos ], element_type, 0, + true /* in */, false /* no out */ ); + JLocalAutoRef jo_element( jni, val.l ); + jni->SetObjectArrayElement( + (jobjectArray) jo_ar.get(), nPos, jo_element.get() ); + jni.ensure_no_exception(); + } + } + break; + case typelib_TypeClass_ANY: + jo_ar.reset( + jni->NewObjectArray( + nElements, m_jni_info->m_class_Object, 0 ) ); + jni.ensure_no_exception(); + if (in_param) + { + uno_Any const * p = (uno_Any const *)seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + jvalue val; + map_to_java( + jni, &val, &p[ nPos ], element_type, 0, + true /* in */, false /* no out */ ); + JLocalAutoRef jo_element( jni, val.l ); + jni->SetObjectArrayElement( + (jobjectArray) jo_ar.get(), nPos, jo_element.get() ); + jni.ensure_no_exception(); + } + } + break; + case typelib_TypeClass_ENUM: + { + OUString const & element_type_name = + OUString::unacquired( &element_type->pTypeName ); + OString class_name( + OUStringToOString( + element_type_name, RTL_TEXTENCODING_JAVA_UTF8 ) ); + JLocalAutoRef jo_enum_class( + jni, find_class( jni, class_name.getStr() ) ); + + jo_ar.reset( + jni->NewObjectArray( + nElements, (jclass) jo_enum_class.get(), 0 ) ); + jni.ensure_no_exception(); + + if (0 < nElements) + { + // call static <enum_class>.fromInt( int ) + OStringBuffer sig_buf( 5 + class_name.getLength() ); + sig_buf.append( RTL_CONSTASCII_STRINGPARAM("(I)L") ); + sig_buf.append( class_name.replace( '.', '/' ) ); + sig_buf.append( ';' ); + OString sig( sig_buf.makeStringAndClear() ); + jmethodID method_id = jni->GetStaticMethodID( + (jclass) jo_enum_class.get(), "fromInt", sig.getStr() ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != method_id ); + + sal_Int32 const * p = (sal_Int32 const *)seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + jvalue arg; + arg.i = p[ nPos ]; + JLocalAutoRef jo_enum( + jni, jni->CallStaticObjectMethodA( + (jclass) jo_enum_class.get(), method_id, &arg ) ); + jni.ensure_no_exception(); + jni->SetObjectArrayElement( + (jobjectArray) jo_ar.get(), nPos, jo_enum.get() ); + jni.ensure_no_exception(); + } + } + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + JNI_type_info const * element_info = + m_jni_info->get_type_info( jni, element_type ); + + jo_ar.reset( + jni->NewObjectArray( nElements, element_info->m_class, 0 ) ); + jni.ensure_no_exception(); + + if (0 < nElements) + { + char * p = (char *)seq->elements; + sal_Int32 nSize = element_info->m_td.get()->nSize; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + jvalue val; + map_to_java( + jni, &val, p + (nSize * nPos), + element_type, element_info, + true /* in */, false /* no out */ ); + JLocalAutoRef jo_element( jni, val.l ); + jni->SetObjectArrayElement( + (jobjectArray) jo_ar.get(), nPos, jo_element.get() ); + jni.ensure_no_exception(); + } + } + break; + } + case typelib_TypeClass_SEQUENCE: + { + OStringBuffer buf( 64 ); + JNI_info::append_sig( + &buf, element_type, false /* use class XInterface */, + false /* '.' instead of '/' */ ); + OString class_name( buf.makeStringAndClear() ); + JLocalAutoRef jo_seq_class( + jni, find_class( jni, class_name.getStr() ) ); + + jo_ar.reset( + jni->NewObjectArray( + nElements, (jclass) jo_seq_class.get(), 0 ) ); + jni.ensure_no_exception(); + + if (0 < nElements) + { + TypeDescr element_td( element_type ); + uno_Sequence ** elements = (uno_Sequence **) seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + jvalue java_data2; + map_to_java( + jni, &java_data2, elements + nPos, element_type, 0, + true /* in */, false /* no out */ ); + JLocalAutoRef jo_seq( jni, java_data2.l ); + jni->SetObjectArrayElement( + (jobjectArray) jo_ar.get(), nPos, jo_seq.get() ); + jni.ensure_no_exception(); + } + } + break; + } + case typelib_TypeClass_INTERFACE: + { + JNI_interface_type_info const * iface_info = + static_cast< JNI_interface_type_info const * >( + m_jni_info->get_type_info( jni, element_type ) ); + + jo_ar.reset( + jni->NewObjectArray( nElements, iface_info->m_class, 0 ) ); + jni.ensure_no_exception(); + + if (0 < nElements) + { + uno_Interface ** pp = (uno_Interface **)seq->elements; + for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos ) + { + uno_Interface * pUnoI = pp[ nPos ]; + if (0 != pUnoI) + { + JLocalAutoRef jo_element( + jni, map_to_java( jni, pUnoI, iface_info ) ); + jni->SetObjectArrayElement( + (jobjectArray) jo_ar.get(), + nPos, jo_element.get() ); + jni.ensure_no_exception(); + } + } + } + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_java():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("] unsupported element type: ") ); + buf.append( OUString::unacquired( &element_type->pTypeName ) ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + + if (out_param) + { + if (0 == java_data->l) + { + JLocalAutoRef jo_element_class( + jni, jni->GetObjectClass( jo_ar.get() ) ); + if (in_param) + { + java_data->l = jni->NewObjectArray( + 1, (jclass) jo_element_class.get(), jo_ar.get() ); + } + else + { + java_data->l = jni->NewObjectArray( + 1, (jclass) jo_element_class.get(), 0 ); + } + jni.ensure_no_exception(); + } + else + { + jni->SetObjectArrayElement( + (jobjectArray) java_data->l, 0, jo_ar.get() ); + jni.ensure_no_exception(); + } + } + else + { + java_data->l = jo_ar.release(); + } + break; + } + case typelib_TypeClass_INTERFACE: + { + JLocalAutoRef jo_iface( jni ); + if (in_param) + { + uno_Interface * pUnoI = *(uno_Interface * const *)uno_data; + if (0 != pUnoI) + { + if (0 == info) + info = m_jni_info->get_type_info( jni, type ); + JNI_interface_type_info const * iface_info = + static_cast< JNI_interface_type_info const * >( info ); + jo_iface.reset( map_to_java( jni, pUnoI, iface_info ) ); + } + } + if (out_param) + { + if (0 == java_data->l) + { + if (0 == info) + info = m_jni_info->get_type_info( jni, type ); + java_data->l = + jni->NewObjectArray( 1, info->m_class, jo_iface.get() ); + jni.ensure_no_exception(); + } + else + { + jni->SetObjectArrayElement( + (jobjectArray) java_data->l, 0, jo_iface.get() ); + jni.ensure_no_exception(); + } + } + else + { + java_data->l = jo_iface.release(); + } + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[map_to_java():") ); + buf.append( OUString::unacquired( &type->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] unsupported type!") ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/jni_uno/jni_helper.h b/bridges/source/jni_uno/jni_helper.h new file mode 100644 index 000000000000..293bf82d868e --- /dev/null +++ b/bridges/source/jni_uno/jni_helper.h @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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. + * + ************************************************************************/ + +#if ! defined INCLUDED_JNI_HELPER_H +#define INCLUDED_JNI_HELPER_H + +#include "jni_base.h" +#include "jni_info.h" + + +namespace jni_uno +{ + +//------------------------------------------------------------------------------ +inline void jstring_to_ustring( + JNI_context const & jni, rtl_uString ** out_ustr, jstring jstr ) +{ + if (0 == jstr) + { + rtl_uString_new( out_ustr ); + } + else + { + jsize len = jni->GetStringLength( jstr ); + ::std::auto_ptr< rtl_mem > mem( + rtl_mem::allocate( + sizeof (rtl_uString) + (len * sizeof (sal_Unicode)) ) ); + rtl_uString * ustr = (rtl_uString *)mem.get(); + jni->GetStringRegion( jstr, 0, len, (jchar *) ustr->buffer ); + jni.ensure_no_exception(); + ustr->refCount = 1; + ustr->length = len; + ustr->buffer[ len ] = '\0'; + mem.release(); + if (0 != *out_ustr) + rtl_uString_release( *out_ustr ); + *out_ustr = ustr; + } +} + +//------------------------------------------------------------------------------ +inline ::rtl::OUString jstring_to_oustring( + JNI_context const & jni, jstring jstr ) +{ + rtl_uString * ustr = 0; + jstring_to_ustring( jni, &ustr, jstr ); + return ::rtl::OUString( ustr, SAL_NO_ACQUIRE ); +} + +//------------------------------------------------------------------------------ +inline jstring ustring_to_jstring( + JNI_context const & jni, rtl_uString const * ustr ) +{ + jstring jstr = jni->NewString( (jchar const *) ustr->buffer, ustr->length ); + jni.ensure_no_exception(); + return jstr; +} + + +//------------------------------------------------------------------------------ +// if inException, does not handle exceptions, in which case returned value will +// be null if exception occurred: +inline jclass find_class( + JNI_context const & jni, char const * class_name, bool inException = false ) +{ + // find_class may be called before the JNI_info is set: + jclass c=0; + jmethodID m; + JNI_info const * info = jni.get_info(); + if (info == 0) { + jni.getClassForName(&c, &m); + if (c == 0) { + if (inException) { + return 0; + } + jni.ensure_no_exception(); + } + } else { + c = info->m_class_Class; + m = info->m_method_Class_forName; + } + return jni.findClass(class_name, c, m, inException); +} + + +//------------------------------------------------------------------------------ +inline jobject create_type( JNI_context const & jni, jclass clazz ) +{ + JNI_info const * jni_info = jni.get_info(); + jvalue arg; + arg.l = clazz; + jobject jo_type = jni->NewObjectA( + jni_info->m_class_Type, jni_info->m_ctor_Type_with_Class, &arg ); + jni.ensure_no_exception(); + return jo_type; +} + +//------------------------------------------------------------------------------ +inline jobject create_type( + JNI_context const & jni, typelib_TypeDescriptionReference * type ) +{ + JNI_info const * jni_info = jni.get_info(); + jvalue args[ 2 ]; + // get type class + args[ 0 ].i = type->eTypeClass; + JLocalAutoRef jo_type_class( + jni, jni->CallStaticObjectMethodA( + jni_info->m_class_TypeClass, + jni_info->m_method_TypeClass_fromInt, args ) ); + jni.ensure_no_exception(); + // construct type + JLocalAutoRef jo_type_name( + jni, ustring_to_jstring( jni, type->pTypeName ) ); + args[ 0 ].l = jo_type_name.get(); + args[ 1 ].l = jo_type_class.get(); + jobject jo_type = jni->NewObjectA( + jni_info->m_class_Type, + jni_info->m_ctor_Type_with_Name_TypeClass, args ); + jni.ensure_no_exception(); + return jo_type; +} + +//------------------------------------------------------------------------------ +inline jobject compute_oid( JNI_context const & jni, jobject jo ) +{ + JNI_info const * jni_info = jni.get_info(); + jvalue arg; + arg.l= jo; + jobject jo_oid = jni->CallStaticObjectMethodA( + jni_info->m_class_UnoRuntime, + jni_info->m_method_UnoRuntime_generateOid, &arg ); + jni.ensure_no_exception(); + return jo_oid; +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/jni_uno/jni_info.cxx b/bridges/source/jni_uno/jni_info.cxx new file mode 100644 index 000000000000..6df598859d0a --- /dev/null +++ b/bridges/source/jni_uno/jni_info.cxx @@ -0,0 +1,999 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 "com/sun/star/uno/RuntimeException.hpp" + +#include "jvmaccess/unovirtualmachine.hxx" +#include "rtl/string.hxx" +#include "rtl/strbuf.hxx" +#include "rtl/ustrbuf.hxx" + +#include "uno/lbnames.h" + + +namespace css = ::com::sun::star; +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; + +namespace jni_uno +{ + +//______________________________________________________________________________ +JNI_type_info::JNI_type_info( + JNI_context const & jni, typelib_TypeDescription * td ) + : m_td( td ), + m_class( 0 ) +{ + m_td.makeComplete(); + if (! m_td.get()->bComplete) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("cannot make type complete: ") ); + buf.append( OUString::unacquired( &m_td.get()->pTypeName ) ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } +} + + +//______________________________________________________________________________ +void JNI_interface_type_info::destroy( JNIEnv * jni_env ) +{ + JNI_type_info::destruct( jni_env ); + jni_env->DeleteGlobalRef( m_proxy_ctor ); + jni_env->DeleteGlobalRef( m_type ); + delete [] m_methods; + delete this; +} + +//______________________________________________________________________________ +JNI_interface_type_info::JNI_interface_type_info( + JNI_context const & jni, typelib_TypeDescription * td_ ) + : JNI_type_info( jni, td_ ) +{ + OSL_ASSERT( typelib_TypeClass_INTERFACE == m_td.get()->eTypeClass ); + + OUString const & uno_name = OUString::unacquired( &m_td.get()->pTypeName ); + JNI_info const * jni_info = jni.get_info(); + + JLocalAutoRef jo_class( + jni, + find_class( + jni, + ( OUStringToOString( uno_name, RTL_TEXTENCODING_JAVA_UTF8 ). + getStr() ) ) ); + JLocalAutoRef jo_type( jni, create_type( jni, (jclass) jo_class.get() ) ); + + // get proxy ctor + jvalue arg; + arg.l = jo_class.get(); + JLocalAutoRef jo_proxy_ctor( + jni, jni->CallStaticObjectMethodA( + jni_info->m_class_JNI_proxy, + jni_info->m_method_JNI_proxy_get_proxy_ctor, &arg ) ); + + if (is_XInterface( m_td.get()->pWeakRef )) + { + m_methods = 0; // no methods + } + else + { + // retrieve method ids for all direct members + try + { + typelib_InterfaceTypeDescription * td = + reinterpret_cast< typelib_InterfaceTypeDescription * >( + m_td.get() ); + m_methods = new jmethodID[ td->nMapFunctionIndexToMemberIndex ]; + sal_Int32 nMethodIndex = 0; + typelib_TypeDescriptionReference ** ppMembers = td->ppMembers; + sal_Int32 nMembers = td->nMembers; + + for ( sal_Int32 nPos = 0; nPos < nMembers; ++nPos ) + { + TypeDescr member_td( ppMembers[ nPos ] ); + + OStringBuffer sig_buf( 64 ); + + if (typelib_TypeClass_INTERFACE_METHOD == + member_td.get()->eTypeClass) // method + { + typelib_InterfaceMethodTypeDescription * method_td = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + member_td.get() ); + + sig_buf.append( '(' ); + for ( sal_Int32 i = 0; i < method_td->nParams; ++i ) + { + typelib_MethodParameter const & param = + method_td->pParams[ i ]; + if (param.bOut) + sig_buf.append( '[' ); + JNI_info::append_sig( &sig_buf, param.pTypeRef ); + } + sig_buf.append( ')' ); + JNI_info::append_sig( &sig_buf, method_td->pReturnTypeRef ); + + OString method_signature( sig_buf.makeStringAndClear() ); + OString method_name( + OUStringToOString( OUString::unacquired( + &method_td->aBase.pMemberName ), + RTL_TEXTENCODING_JAVA_UTF8 ) ); + + m_methods[ nMethodIndex ] = jni->GetMethodID( + (jclass) jo_class.get(), method_name.getStr(), + method_signature.getStr() ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_methods[ nMethodIndex ] ); + ++nMethodIndex; + } + else // attribute + { + OSL_ASSERT( + typelib_TypeClass_INTERFACE_ATTRIBUTE == + member_td.get()->eTypeClass ); + typelib_InterfaceAttributeTypeDescription * attribute_td = + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member_td.get() ); + + // type sig + JNI_info::append_sig( + &sig_buf, attribute_td->pAttributeTypeRef ); + OString type_sig( sig_buf.makeStringAndClear() ); + sig_buf.ensureCapacity( 64 ); + // member name + OUString const & member_name = + OUString::unacquired( + &attribute_td->aBase.pMemberName ); + + // getter + sig_buf.append( RTL_CONSTASCII_STRINGPARAM("()") ); + sig_buf.append( type_sig ); + OString method_signature( sig_buf.makeStringAndClear() ); + OUStringBuffer name_buf( 3 + member_name.getLength() ); + name_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("get") ); + name_buf.append( member_name ); + OString method_name( + OUStringToOString( + name_buf.makeStringAndClear(), + RTL_TEXTENCODING_JAVA_UTF8 ) ); + m_methods[ nMethodIndex ] = jni->GetMethodID( + (jclass) jo_class.get(), method_name.getStr(), + method_signature.getStr() ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_methods[ nMethodIndex ] ); + ++nMethodIndex; + if (! attribute_td->bReadOnly) + { + // setter + sig_buf.ensureCapacity( 64 ); + sig_buf.append( '(' ); + sig_buf.append( type_sig ); + sig_buf.append( RTL_CONSTASCII_STRINGPARAM(")V") ); + method_signature = sig_buf.makeStringAndClear(); + name_buf.ensureCapacity( 3 + member_name.getLength() ); + name_buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("set") ); + name_buf.append( member_name ); + method_name = OUStringToOString( + name_buf.makeStringAndClear(), + RTL_TEXTENCODING_JAVA_UTF8 ); + m_methods[ nMethodIndex ] = jni->GetMethodID( + (jclass) jo_class.get(), method_name.getStr(), + method_signature.getStr() ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_methods[ nMethodIndex ] ); + ++nMethodIndex; + } + } + } + } + catch (...) + { + delete [] m_methods; + throw; + } + } + m_class = (jclass) jni->NewGlobalRef( jo_class.get() ); + m_type = jni->NewGlobalRef( jo_type.get() ); + m_proxy_ctor = jni->NewGlobalRef( jo_proxy_ctor.get() ); +} + + +//______________________________________________________________________________ +void JNI_compound_type_info::destroy( JNIEnv * jni_env ) +{ + JNI_type_info::destruct( jni_env ); + delete [] m_fields; + delete this; +} + +//______________________________________________________________________________ +JNI_compound_type_info::JNI_compound_type_info( + JNI_context const & jni, typelib_TypeDescription * td_ ) + : JNI_type_info( jni, td_ ), + m_exc_ctor( 0 ), + m_fields( 0 ) +{ + OSL_ASSERT( typelib_TypeClass_STRUCT == m_td.get()->eTypeClass || + typelib_TypeClass_EXCEPTION == m_td.get()->eTypeClass ); + typelib_CompoundTypeDescription * td = + reinterpret_cast< typelib_CompoundTypeDescription * >( m_td.get() ); + + OUString const & uno_name = + OUString::unacquired( &((typelib_TypeDescription *)td)->pTypeName ); + + // Erase type arguments of instantiated polymorphic struct types: + OUString nucleus; + sal_Int32 i = uno_name.indexOf( '<' ); + if ( i < 0 ) { + nucleus = uno_name; + } else { + nucleus = uno_name.copy( 0, i ); + } + JLocalAutoRef jo_class( + jni, + find_class( + jni, + OUStringToOString( + nucleus, RTL_TEXTENCODING_JAVA_UTF8 ).getStr() ) ); + + JNI_info const * jni_info = jni.get_info(); + + if (typelib_TypeClass_EXCEPTION == m_td.get()->eTypeClass) + { + // retrieve exc ctor( msg ) + m_exc_ctor = jni->GetMethodID( + (jclass) jo_class.get(), "<init>", "(Ljava/lang/String;)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_exc_ctor ); + } + + // retrieve info for base type + typelib_TypeDescription * base_td = + reinterpret_cast< typelib_TypeDescription * >( + td->pBaseTypeDescription ); + m_base = (0 == base_td ? 0 : jni_info->get_type_info( jni, base_td )); + + try + { + if (type_equals( + ((typelib_TypeDescription *)td)->pWeakRef, + jni_info->m_Exception_type.getTypeLibType() ) || + type_equals( + ((typelib_TypeDescription *)td)->pWeakRef, + jni_info->m_RuntimeException_type.getTypeLibType() )) + { + m_fields = new jfieldID[ 2 ]; + m_fields[ 0 ] = 0; // special Throwable.getMessage() + // field Context + m_fields[ 1 ] = jni->GetFieldID( + (jclass) jo_class.get(), "Context", "Ljava/lang/Object;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_fields[ 1 ] ); + } + else + { + // retrieve field ids for all direct members + sal_Int32 nMembers = td->nMembers; + m_fields = new jfieldID[ nMembers ]; + + for ( sal_Int32 nPos = 0; nPos < nMembers; ++nPos ) + { + OString sig; + if (td->aBase.eTypeClass == typelib_TypeClass_STRUCT + && reinterpret_cast< typelib_StructTypeDescription * >( + td)->pParameterizedTypes != 0 + && reinterpret_cast< typelib_StructTypeDescription * >( + td)->pParameterizedTypes[nPos]) + { + sig = OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;")); + } else { + OStringBuffer sig_buf( 32 ); + JNI_info::append_sig( &sig_buf, td->ppTypeRefs[ nPos ] ); + sig = sig_buf.makeStringAndClear(); + } + + OString member_name( + OUStringToOString( + OUString::unacquired( &td->ppMemberNames[ nPos ] ), + RTL_TEXTENCODING_JAVA_UTF8 ) ); + + m_fields[ nPos ] = jni->GetFieldID( + (jclass) jo_class.get(), member_name.getStr(), + sig.getStr() ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_fields[ nPos ] ); + } + } + } + catch (...) + { + delete [] m_fields; + throw; + } + + m_class = (jclass) jni->NewGlobalRef( jo_class.get() ); +} + + +//______________________________________________________________________________ +JNI_type_info const * JNI_info::create_type_info( + JNI_context const & jni, typelib_TypeDescription * td ) const +{ + OUString const & uno_name = OUString::unacquired( &td->pTypeName ); + + JNI_type_info * new_info; + switch (td->eTypeClass) + { + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + new_info = new JNI_compound_type_info( jni, td ); + break; + } + case typelib_TypeClass_INTERFACE: + { + new_info = new JNI_interface_type_info( jni, td ); + break; + } + default: + { + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("type info not supported for ") ); + buf.append( uno_name ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + + // look up + JNI_type_info * info; + ClearableMutexGuard guard( m_mutex ); + JNI_type_info_holder & holder = m_type_map[ uno_name ]; + if (0 == holder.m_info) // new insertion + { + holder.m_info = new_info; + guard.clear(); + info = new_info; + } + else // inserted in the meantime + { + info = holder.m_info; + guard.clear(); + new_info->destroy( jni.get_jni_env() ); + } + return info; +} + +//______________________________________________________________________________ +JNI_type_info const * JNI_info::get_type_info( + JNI_context const & jni, typelib_TypeDescription * td ) const +{ + if (is_XInterface( td->pWeakRef )) + { + return m_XInterface_type_info; + } + + OUString const & uno_name = OUString::unacquired( &td->pTypeName ); + JNI_type_info const * info; + ClearableMutexGuard guard( m_mutex ); + + t_str2type::const_iterator iFind( m_type_map.find( uno_name ) ); + if (iFind == m_type_map.end()) + { + guard.clear(); + info = create_type_info( jni, td ); + } + else + { + info = iFind->second.m_info; + } + + return info; +} + +//______________________________________________________________________________ +JNI_type_info const * JNI_info::get_type_info( + JNI_context const & jni, typelib_TypeDescriptionReference * type ) const +{ + if (is_XInterface( type )) + { + return m_XInterface_type_info; + } + + OUString const & uno_name = OUString::unacquired( &type->pTypeName ); + JNI_type_info const * info; + ClearableMutexGuard guard( m_mutex ); + t_str2type::const_iterator iFind( m_type_map.find( uno_name ) ); + if (iFind == m_type_map.end()) + { + guard.clear(); + TypeDescr td( type ); + info = create_type_info( jni, td.get() ); + } + else + { + info = iFind->second.m_info; + } + + return info; +} + +//______________________________________________________________________________ +JNI_type_info const * JNI_info::get_type_info( + JNI_context const & jni, OUString const & uno_name ) const +{ + if (uno_name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") )) + { + return m_XInterface_type_info; + } + + JNI_type_info const * info; + ClearableMutexGuard guard( m_mutex ); + t_str2type::const_iterator iFind( m_type_map.find( uno_name ) ); + if (iFind == m_type_map.end()) + { + guard.clear(); + css::uno::TypeDescription td( uno_name ); + if (! td.is()) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("UNO type not found: ") ); + buf.append( uno_name ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + info = create_type_info( jni, td.get() ); + } + else + { + info = iFind->second.m_info; + } + + return info; +} + +//______________________________________________________________________________ +JNI_info::JNI_info( + JNIEnv * jni_env, jobject class_loader, jclass classClass, + jmethodID methodForName ) + : m_class_Class( classClass ), + m_method_Class_forName( methodForName ), + m_class_JNI_proxy( 0 ), + m_XInterface_queryInterface_td( + (reinterpret_cast< typelib_InterfaceTypeDescription * >( + css::uno::TypeDescription( + ::getCppuType( + (css::uno::Reference< css::uno::XInterface > const *)0 ) ) + .get())->ppMembers[ 0 ] ) ), + m_Exception_type( ::getCppuType( (css::uno::Exception const *)0 ) ), + m_RuntimeException_type( + ::getCppuType( (css::uno::RuntimeException const *)0 ) ), + m_void_type( ::getCppuVoidType() ), + m_XInterface_type_info( 0 ) +{ + JNI_context jni( this, jni_env, class_loader ); // !no proper jni_info! + + // class lookup + JLocalAutoRef jo_Object( + jni, find_class( jni, "java.lang.Object" ) ); + JLocalAutoRef jo_Class( + jni, find_class( jni, "java.lang.Class" ) ); + JLocalAutoRef jo_Throwable( + jni, find_class( jni, "java.lang.Throwable" ) ); + JLocalAutoRef jo_Character( + jni, find_class( jni, "java.lang.Character" ) ); + JLocalAutoRef jo_Boolean( + jni, find_class( jni, "java.lang.Boolean" ) ); + JLocalAutoRef jo_Byte( + jni, find_class( jni, "java.lang.Byte" ) ); + JLocalAutoRef jo_Short( + jni, find_class( jni, "java.lang.Short" ) ); + JLocalAutoRef jo_Integer( + jni, find_class( jni, "java.lang.Integer" ) ); + JLocalAutoRef jo_Long( + jni, find_class( jni, "java.lang.Long" ) ); + JLocalAutoRef jo_Float( + jni, find_class( jni, "java.lang.Float" ) ); + JLocalAutoRef jo_Double( + jni, find_class( jni, "java.lang.Double" ) ); + JLocalAutoRef jo_String( + jni, find_class( jni, "java.lang.String" ) ); + JLocalAutoRef jo_RuntimeException( + jni, find_class( jni, "com.sun.star.uno.RuntimeException" ) ); + JLocalAutoRef jo_UnoRuntime( + jni, find_class( jni, "com.sun.star.uno.UnoRuntime" ) ); + JLocalAutoRef jo_Any( + jni, find_class( jni, "com.sun.star.uno.Any" ) ); + JLocalAutoRef jo_Enum( + jni, find_class( jni, "com.sun.star.uno.Enum" ) ); + JLocalAutoRef jo_Type( + jni, find_class( jni, "com.sun.star.uno.Type" ) ); + JLocalAutoRef jo_TypeClass( + jni, find_class( jni, "com.sun.star.uno.TypeClass" ) ); + JLocalAutoRef jo_IEnvironment( + jni, find_class( jni, "com.sun.star.uno.IEnvironment" ) ); + JLocalAutoRef jo_JNI_proxy( + jni, find_class( jni, "com.sun.star.bridges.jni_uno.JNI_proxy" ) ); + + // method Object.toString() + m_method_Object_toString = jni->GetMethodID( + (jclass) jo_Object.get(), "toString", "()Ljava/lang/String;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Object_toString ); + // method Class.getName() + m_method_Class_getName = jni->GetMethodID( + (jclass) jo_Class.get(), "getName", "()Ljava/lang/String;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Class_getName ); + + // method Throwable.getMessage() + m_method_Throwable_getMessage = jni->GetMethodID( + (jclass) jo_Throwable.get(), "getMessage", "()Ljava/lang/String;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Throwable_getMessage ); + + // method Character.charValue() + m_method_Character_charValue = jni->GetMethodID( + (jclass) jo_Character.get(), "charValue", "()C" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Character_charValue ); + // method Boolean.booleanValue() + m_method_Boolean_booleanValue = jni->GetMethodID( + (jclass) jo_Boolean.get(), "booleanValue", "()Z" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Boolean_booleanValue ); + // method Byte.byteValue() + m_method_Byte_byteValue = jni->GetMethodID( + (jclass) jo_Byte.get(), "byteValue", "()B" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Byte_byteValue ); + // method Short.shortValue() + m_method_Short_shortValue = jni->GetMethodID( + (jclass) jo_Short.get(), "shortValue", "()S" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Short_shortValue ); + // method Integer.intValue() + m_method_Integer_intValue = jni->GetMethodID( + (jclass) jo_Integer.get(), "intValue", "()I" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Integer_intValue ); + // method Long.longValue() + m_method_Long_longValue = jni->GetMethodID( + (jclass) jo_Long.get(), "longValue", "()J" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Long_longValue ); + // method Float.floatValue() + m_method_Float_floatValue = jni->GetMethodID( + (jclass) jo_Float.get(), "floatValue", "()F" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Float_floatValue ); + // method Double.doubleValue() + m_method_Double_doubleValue = jni->GetMethodID( + (jclass) jo_Double.get(), "doubleValue", "()D" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_Double_doubleValue ); + + // ctor Character( char ) + m_ctor_Character_with_char = jni->GetMethodID( + (jclass) jo_Character.get(), "<init>", "(C)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Character_with_char ); + // ctor Boolean( boolean ) + m_ctor_Boolean_with_boolean = jni->GetMethodID( + (jclass) jo_Boolean.get(), "<init>", "(Z)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Boolean_with_boolean ); + // ctor Byte( byte ) + m_ctor_Byte_with_byte = jni->GetMethodID( + (jclass) jo_Byte.get(), "<init>", "(B)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Byte_with_byte ); + // ctor Short( short ) + m_ctor_Short_with_short = jni->GetMethodID( + (jclass) jo_Short.get(), "<init>", "(S)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Short_with_short ); + // ctor Integer( int ) + m_ctor_Integer_with_int = jni->GetMethodID( + (jclass) jo_Integer.get(), "<init>", "(I)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Integer_with_int ); + // ctor Long( long ) + m_ctor_Long_with_long = jni->GetMethodID( + (jclass) jo_Long.get(), "<init>", "(J)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Long_with_long ); + // ctor Float( float ) + m_ctor_Float_with_float = jni->GetMethodID( + (jclass) jo_Float.get(), "<init>", "(F)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Float_with_float ); + // ctor Double( double ) + m_ctor_Double_with_double = jni->GetMethodID( + (jclass) jo_Double.get(), "<init>", "(D)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Double_with_double ); + + // static method UnoRuntime.generateOid() + m_method_UnoRuntime_generateOid = jni->GetStaticMethodID( + (jclass) jo_UnoRuntime.get(), + "generateOid", "(Ljava/lang/Object;)Ljava/lang/String;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_UnoRuntime_generateOid ); + // static method UnoRuntime.queryInterface() + m_method_UnoRuntime_queryInterface = jni->GetStaticMethodID( + (jclass) jo_UnoRuntime.get(), + "queryInterface", + "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)Ljava/lang/Object;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_UnoRuntime_queryInterface ); + + // field Enum.m_value + m_field_Enum_m_value = jni->GetFieldID( + (jclass) jo_Enum.get(), "m_value", "I" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_field_Enum_m_value ); + + // static method TypeClass.fromInt() + m_method_TypeClass_fromInt = jni->GetStaticMethodID( + (jclass) jo_TypeClass.get(), + "fromInt", "(I)Lcom/sun/star/uno/TypeClass;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_TypeClass_fromInt ); + + // ctor Type( Class ) + m_ctor_Type_with_Class = jni->GetMethodID( + (jclass) jo_Type.get(), "<init>", "(Ljava/lang/Class;)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Type_with_Class ); + // ctor Type( String, TypeClass ) + m_ctor_Type_with_Name_TypeClass = jni->GetMethodID( + (jclass) jo_Type.get(), + "<init>", "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Type_with_Name_TypeClass ); + // field Type._typeName + m_field_Type__typeName = jni->GetFieldID( + (jclass) jo_Type.get(), "_typeName", "Ljava/lang/String;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_field_Type__typeName ); + + // ctor Any( Type, Object ) + m_ctor_Any_with_Type_Object = jni->GetMethodID( + (jclass) jo_Any.get(), + "<init>", "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_ctor_Any_with_Type_Object ); + + // field Any._type + m_field_Any__type = jni->GetFieldID( + (jclass) jo_Any.get(), "_type", "Lcom/sun/star/uno/Type;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_field_Any__type ); + // field Any._object + m_field_Any__object = jni->GetFieldID( + (jclass) jo_Any.get(), "_object", "Ljava/lang/Object;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_field_Any__object ); + + // method IEnvironment.getRegisteredInterface() + m_method_IEnvironment_getRegisteredInterface = jni->GetMethodID( + (jclass) jo_IEnvironment.get(), + "getRegisteredInterface", + "(Ljava/lang/String;Lcom/sun/star/uno/Type;)Ljava/lang/Object;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_IEnvironment_getRegisteredInterface ); + // method IEnvironment.registerInterface() + m_method_IEnvironment_registerInterface = jni->GetMethodID( + (jclass) jo_IEnvironment.get(), "registerInterface", + "(Ljava/lang/Object;[Ljava/lang/String;Lcom/sun/star/uno/Type;)" + "Ljava/lang/Object;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_IEnvironment_registerInterface ); + + // static method JNI_proxy.get_proxy_ctor() + m_method_JNI_proxy_get_proxy_ctor = jni->GetStaticMethodID( + (jclass) jo_JNI_proxy.get(), "get_proxy_ctor", + "(Ljava/lang/Class;)Ljava/lang/reflect/Constructor;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_JNI_proxy_get_proxy_ctor ); + // static method JNI_proxy.create() + m_method_JNI_proxy_create = jni->GetStaticMethodID( + (jclass) jo_JNI_proxy.get(), "create", + "(JLcom/sun/star/uno/IEnvironment;JJLcom/sun/star/uno/Type;Ljava/lang" + "/String;Ljava/lang/reflect/Constructor;)Ljava/lang/Object;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_method_JNI_proxy_create ); + // field JNI_proxy.m_receiver_handle + m_field_JNI_proxy_m_receiver_handle = jni->GetFieldID( + (jclass) jo_JNI_proxy.get(), "m_receiver_handle", "J" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_field_JNI_proxy_m_receiver_handle ); + // field JNI_proxy.m_td_handle + m_field_JNI_proxy_m_td_handle = jni->GetFieldID( + (jclass) jo_JNI_proxy.get(), "m_td_handle", "J" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_field_JNI_proxy_m_td_handle ); + // field JNI_proxy.m_type + m_field_JNI_proxy_m_type = jni->GetFieldID( + (jclass) jo_JNI_proxy.get(), "m_type", "Lcom/sun/star/uno/Type;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_field_JNI_proxy_m_type ); + // field JNI_proxy.m_oid + m_field_JNI_proxy_m_oid = jni->GetFieldID( + (jclass) jo_JNI_proxy.get(), "m_oid", "Ljava/lang/String;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != m_field_JNI_proxy_m_oid ); + + // get java env + OUString java_env_type_name( RTL_CONSTASCII_USTRINGPARAM(UNO_LB_JAVA) ); + JLocalAutoRef jo_java( + jni, ustring_to_jstring( jni, java_env_type_name.pData ) ); + jvalue args[ 2 ]; + args[ 0 ].l = jo_java.get(); + args[ 1 ].l = 0; + jmethodID method_getEnvironment = jni->GetStaticMethodID( + (jclass) jo_UnoRuntime.get(), "getEnvironment", + "(Ljava/lang/String;Ljava/lang/Object;)" + "Lcom/sun/star/uno/IEnvironment;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != method_getEnvironment ); + JLocalAutoRef jo_java_env( + jni, jni->CallStaticObjectMethodA( + (jclass) jo_UnoRuntime.get(), method_getEnvironment, args ) ); + + // get com.sun.star.uno.Any.VOID + jfieldID field_Any_VOID = jni->GetStaticFieldID( + (jclass) jo_Any.get(), "VOID", "Lcom/sun/star/uno/Any;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != field_Any_VOID ); + JLocalAutoRef jo_Any_VOID( + jni, jni->GetStaticObjectField( + (jclass) jo_Any.get(), field_Any_VOID ) ); + // get com.sun.star.uno.Type.UNSIGNED_SHORT + jfieldID field_Type_UNSIGNED_SHORT = jni->GetStaticFieldID( + (jclass) jo_Type.get(), "UNSIGNED_SHORT", "Lcom/sun/star/uno/Type;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != field_Type_UNSIGNED_SHORT ); + JLocalAutoRef jo_Type_UNSIGNED_SHORT( + jni, jni->GetStaticObjectField( + (jclass) jo_Type.get(), field_Type_UNSIGNED_SHORT ) ); + // get com.sun.star.uno.Type.UNSIGNED_LONG + jfieldID field_Type_UNSIGNED_LONG = jni->GetStaticFieldID( + (jclass) jo_Type.get(), "UNSIGNED_LONG", "Lcom/sun/star/uno/Type;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != field_Type_UNSIGNED_LONG ); + JLocalAutoRef jo_Type_UNSIGNED_LONG( + jni, jni->GetStaticObjectField( + (jclass) jo_Type.get(), field_Type_UNSIGNED_LONG ) ); + // get com.sun.star.uno.Type.UNSIGNED_HYPER + jfieldID field_Type_UNSIGNED_HYPER = jni->GetStaticFieldID( + (jclass) jo_Type.get(), "UNSIGNED_HYPER", "Lcom/sun/star/uno/Type;" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != field_Type_UNSIGNED_HYPER ); + JLocalAutoRef jo_Type_UNSIGNED_HYPER( + jni, jni->GetStaticObjectField( + (jclass) jo_Type.get(), field_Type_UNSIGNED_HYPER ) ); + + // make global refs + m_class_UnoRuntime = + (jclass) jni->NewGlobalRef( jo_UnoRuntime.get() ); + m_class_RuntimeException = + (jclass) jni->NewGlobalRef( jo_RuntimeException.get() ); + m_class_Any = + (jclass) jni->NewGlobalRef( jo_Any.get() ); + m_class_Type = + (jclass) jni->NewGlobalRef( jo_Type.get() ); + m_class_TypeClass = + (jclass) jni->NewGlobalRef( jo_TypeClass.get() ); + m_class_JNI_proxy = + (jclass) jni->NewGlobalRef( jo_JNI_proxy.get() ); + + m_class_Character = + (jclass) jni->NewGlobalRef( jo_Character.get() ); + m_class_Boolean = + (jclass) jni->NewGlobalRef( jo_Boolean.get() ); + m_class_Byte = + (jclass) jni->NewGlobalRef( jo_Byte.get() ); + m_class_Short = + (jclass) jni->NewGlobalRef( jo_Short.get() ); + m_class_Integer = + (jclass) jni->NewGlobalRef( jo_Integer.get() ); + m_class_Long = + (jclass) jni->NewGlobalRef( jo_Long.get() ); + m_class_Float = + (jclass) jni->NewGlobalRef( jo_Float.get() ); + m_class_Double = + (jclass) jni->NewGlobalRef( jo_Double.get() ); + m_class_String = + (jclass) jni->NewGlobalRef( jo_String.get() ); + m_class_Object = + (jclass) jni->NewGlobalRef( jo_Object.get() ); + m_class_Class = + (jclass) jni->NewGlobalRef( m_class_Class ); + + m_object_Any_VOID = + jni->NewGlobalRef( jo_Any_VOID.get() ); + m_object_Type_UNSIGNED_SHORT = + jni->NewGlobalRef( jo_Type_UNSIGNED_SHORT.get() ); + m_object_Type_UNSIGNED_LONG = + jni->NewGlobalRef( jo_Type_UNSIGNED_LONG.get() ); + m_object_Type_UNSIGNED_HYPER = + jni->NewGlobalRef( jo_Type_UNSIGNED_HYPER.get() ); + m_object_java_env = jni->NewGlobalRef( jo_java_env.get() ); + + try + { + css::uno::TypeDescription XInterface_td( + ::getCppuType( + (css::uno::Reference< css::uno::XInterface > const *)0 ) ); + m_XInterface_type_info = + new JNI_interface_type_info( jni, XInterface_td.get() ); + } + catch (...) + { + destruct( jni_env ); + throw; + } +} + +//______________________________________________________________________________ +void JNI_info::destruct( JNIEnv * jni_env ) +{ + t_str2type::const_iterator iPos( m_type_map.begin() ); + t_str2type::const_iterator const iEnd( m_type_map.begin() ); + for ( ; iPos != iEnd; ++iPos ) + { + iPos->second.m_info->destroy( jni_env ); + } + if (0 != m_XInterface_type_info) + { + const_cast< JNI_interface_type_info * >( + m_XInterface_type_info )->destroy( jni_env ); + } + + // free global refs + jni_env->DeleteGlobalRef( m_object_java_env ); + jni_env->DeleteGlobalRef( m_object_Any_VOID ); + jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_SHORT ); + jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_LONG ); + jni_env->DeleteGlobalRef( m_object_Type_UNSIGNED_HYPER ); + + jni_env->DeleteGlobalRef( m_class_Class ); + jni_env->DeleteGlobalRef( m_class_Object ); + jni_env->DeleteGlobalRef( m_class_String ); + jni_env->DeleteGlobalRef( m_class_Double ); + jni_env->DeleteGlobalRef( m_class_Float ); + jni_env->DeleteGlobalRef( m_class_Long ); + jni_env->DeleteGlobalRef( m_class_Integer ); + jni_env->DeleteGlobalRef( m_class_Short ); + jni_env->DeleteGlobalRef( m_class_Byte ); + jni_env->DeleteGlobalRef( m_class_Boolean ); + jni_env->DeleteGlobalRef( m_class_Character ); + + jni_env->DeleteGlobalRef( m_class_JNI_proxy ); + jni_env->DeleteGlobalRef( m_class_RuntimeException ); + jni_env->DeleteGlobalRef( m_class_UnoRuntime ); + jni_env->DeleteGlobalRef( m_class_TypeClass ); + jni_env->DeleteGlobalRef( m_class_Type ); + jni_env->DeleteGlobalRef( m_class_Any ); +} + +//______________________________________________________________________________ +JNI_info const * JNI_info::get_jni_info( + rtl::Reference< jvmaccess::UnoVirtualMachine > const & uno_vm ) +{ + // !!!no JNI_info available at JNI_context!!! + ::jvmaccess::VirtualMachine::AttachGuard guard( + uno_vm->getVirtualMachine() ); + JNIEnv * jni_env = guard.getEnvironment(); + JNI_context jni( + 0, jni_env, static_cast< jobject >(uno_vm->getClassLoader()) ); + + jclass jo_class; + jmethodID jo_forName; + jni.getClassForName( &jo_class, &jo_forName ); + jni.ensure_no_exception(); + JLocalAutoRef jo_JNI_info_holder( + jni, + jni.findClass( + "com.sun.star.bridges.jni_uno.JNI_info_holder", jo_class, + jo_forName, false ) ); + // field JNI_info_holder.m_jni_info_handle + jfieldID field_s_jni_info_handle = + jni->GetStaticFieldID( + (jclass) jo_JNI_info_holder.get(), "s_jni_info_handle", "J" ); + jni.ensure_no_exception(); + OSL_ASSERT( 0 != field_s_jni_info_handle ); + + JNI_info const * jni_info = + reinterpret_cast< JNI_info const * >( + jni->GetStaticLongField( + (jclass) jo_JNI_info_holder.get(), field_s_jni_info_handle ) ); + if (0 == jni_info) // un-initialized? + { + JNI_info * new_info = new JNI_info( + jni_env, static_cast< jobject >(uno_vm->getClassLoader()), jo_class, + jo_forName ); + + ClearableMutexGuard g( Mutex::getGlobalMutex() ); + jni_info = + reinterpret_cast< JNI_info const * >( + jni->GetStaticLongField( + (jclass) jo_JNI_info_holder.get(), + field_s_jni_info_handle ) ); + if (0 == jni_info) // still un-initialized? + { + jni->SetStaticLongField( + (jclass) jo_JNI_info_holder.get(), field_s_jni_info_handle, + reinterpret_cast< jlong >( new_info ) ); + jni_info = new_info; + } + else + { + g.clear(); + new_info->destroy( jni_env ); + } + } + + return jni_info; +} + +} + +extern "C" +{ + +//------------------------------------------------------------------------------ +JNIEXPORT void +JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1info_1holder_finalize__J( + JNIEnv * jni_env, jobject, jlong jni_info_handle ) + SAL_THROW_EXTERN_C() +{ + ::jni_uno::JNI_info * jni_info = + reinterpret_cast< ::jni_uno::JNI_info * >( jni_info_handle ); + jni_info->destroy( jni_env ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/jni_uno/jni_info.h b/bridges/source/jni_uno/jni_info.h new file mode 100644 index 000000000000..a356be272e04 --- /dev/null +++ b/bridges/source/jni_uno/jni_info.h @@ -0,0 +1,378 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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. + * + ************************************************************************/ + +#if ! defined INCLUDED_JNI_INFO_H +#define INCLUDED_JNI_INFO_H + +#include <boost/unordered_map.hpp> + +#include "jni_base.h" + +#include "osl/mutex.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "rtl/strbuf.hxx" + +#include "uno/environment.h" +#include "typelib/typedescription.hxx" + +#include "com/sun/star/uno/Type.hxx" + +namespace jvmaccess { class UnoVirtualMachine; } + +namespace jni_uno +{ + +//------------------------------------------------------------------------------ +inline bool type_equals( + typelib_TypeDescriptionReference * type1, + typelib_TypeDescriptionReference * type2 ) +{ + if (type1 == type2) + return true; + ::rtl::OUString const & name1 = + ::rtl::OUString::unacquired( &type1->pTypeName ); + ::rtl::OUString const & name2 = + ::rtl::OUString::unacquired( &type2->pTypeName ); + return ((type1->eTypeClass == type2->eTypeClass) && name1.equals( name2 )); +} + +//------------------------------------------------------------------------------ +inline bool is_XInterface( typelib_TypeDescriptionReference * type ) +{ + return ((typelib_TypeClass_INTERFACE == type->eTypeClass) && + ::rtl::OUString::unacquired( &type->pTypeName ).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") )); +} + +//============================================================================== +struct JNI_type_info +{ + ::com::sun::star::uno::TypeDescription m_td; + jclass m_class; + + virtual void destroy( JNIEnv * jni_env ) = 0; +protected: + inline void destruct( JNIEnv * jni_env ) + { jni_env->DeleteGlobalRef( m_class ); } + virtual inline ~JNI_type_info() {} + explicit JNI_type_info( + JNI_context const & jni, typelib_TypeDescription * td ); +}; + +//============================================================================== +struct JNI_interface_type_info : public JNI_type_info +{ + jobject m_proxy_ctor; // proxy ctor + jobject m_type; + // sorted via typelib function index + jmethodID * m_methods; + + virtual void destroy( JNIEnv * jni_env ); + explicit JNI_interface_type_info( + JNI_context const & jni, typelib_TypeDescription * td ); +}; + +//============================================================================== +struct JNI_compound_type_info : public JNI_type_info +{ + JNI_type_info const * m_base; + // ctor( msg ) for exceptions + jmethodID m_exc_ctor; + // sorted via typelib member index + jfieldID * m_fields; + + virtual void destroy( JNIEnv * jni_env ); + explicit JNI_compound_type_info( + JNI_context const & jni, typelib_TypeDescription * td ); +}; + +//============================================================================== +struct JNI_type_info_holder +{ + JNI_type_info * m_info; + inline JNI_type_info_holder() + : m_info( 0 ) + {} +}; + +typedef ::boost::unordered_map< + ::rtl::OUString, JNI_type_info_holder, ::rtl::OUStringHash > t_str2type; + +//============================================================================== +class JNI_info +{ + mutable ::osl::Mutex m_mutex; + mutable t_str2type m_type_map; + +public: + // These two are needed very early by find_class from within the ctor: + jclass m_class_Class; + jmethodID m_method_Class_forName; + + // + jobject m_object_java_env; + jobject m_object_Any_VOID; + jobject m_object_Type_UNSIGNED_SHORT; + jobject m_object_Type_UNSIGNED_LONG; + jobject m_object_Type_UNSIGNED_HYPER; + + // + jclass m_class_Object; + jclass m_class_Character; + jclass m_class_Boolean; + jclass m_class_Byte; + jclass m_class_Short; + jclass m_class_Integer; + jclass m_class_Long; + jclass m_class_Float; + jclass m_class_Double; + jclass m_class_String; + + jclass m_class_UnoRuntime; + jclass m_class_RuntimeException; + jclass m_class_Any; + jclass m_class_Type; + jclass m_class_TypeClass; + jclass m_class_JNI_proxy; + + // + jmethodID m_method_Object_toString; + jmethodID m_method_Class_getName; + jmethodID m_method_Throwable_getMessage; + jmethodID m_ctor_Character_with_char; + jmethodID m_ctor_Boolean_with_boolean; + jmethodID m_ctor_Byte_with_byte; + jmethodID m_ctor_Short_with_short; + jmethodID m_ctor_Integer_with_int; + jmethodID m_ctor_Long_with_long; + jmethodID m_ctor_Float_with_float; + jmethodID m_ctor_Double_with_double; + jmethodID m_method_Boolean_booleanValue; + jmethodID m_method_Byte_byteValue; + jmethodID m_method_Character_charValue; + jmethodID m_method_Double_doubleValue; + jmethodID m_method_Float_floatValue; + jmethodID m_method_Integer_intValue; + jmethodID m_method_Long_longValue; + jmethodID m_method_Short_shortValue; + + // + jmethodID m_method_IEnvironment_getRegisteredInterface; + jmethodID m_method_IEnvironment_registerInterface; + jmethodID m_method_UnoRuntime_generateOid; + jmethodID m_method_UnoRuntime_queryInterface; + jmethodID m_ctor_Any_with_Type_Object; + jfieldID m_field_Any__type; + jfieldID m_field_Any__object; + jmethodID m_ctor_Type_with_Class; + jmethodID m_ctor_Type_with_Name_TypeClass; + jfieldID m_field_Type__typeName; + jmethodID m_method_TypeClass_fromInt; + jfieldID m_field_Enum_m_value; + + // + jmethodID m_method_JNI_proxy_get_proxy_ctor; + jmethodID m_method_JNI_proxy_create; + jfieldID m_field_JNI_proxy_m_receiver_handle; + jfieldID m_field_JNI_proxy_m_td_handle; + jfieldID m_field_JNI_proxy_m_type; + jfieldID m_field_JNI_proxy_m_oid; + + // + ::com::sun::star::uno::TypeDescription m_XInterface_queryInterface_td; + ::com::sun::star::uno::Type const & m_Exception_type; + ::com::sun::star::uno::Type const & m_RuntimeException_type; + ::com::sun::star::uno::Type const & m_void_type; + // + JNI_interface_type_info const * m_XInterface_type_info; + + // + JNI_type_info const * get_type_info( + JNI_context const & jni, + typelib_TypeDescription * type ) const; + JNI_type_info const * get_type_info( + JNI_context const & jni, + typelib_TypeDescriptionReference * type ) const; + JNI_type_info const * get_type_info( + JNI_context const & jni, + ::rtl::OUString const & uno_name ) const; + // + inline static void append_sig( + ::rtl::OStringBuffer * buf, typelib_TypeDescriptionReference * type, + bool use_Object_for_type_XInterface = true, bool use_slashes = true ); + + // get this + static JNI_info const * get_jni_info( + rtl::Reference< jvmaccess::UnoVirtualMachine > const & uno_vm ); + inline void destroy( JNIEnv * jni_env ); + +private: + JNI_type_info const * create_type_info( + JNI_context const & jni, typelib_TypeDescription * td ) const; + + void destruct( JNIEnv * jni_env ); + + JNI_info( JNIEnv * jni_env, jobject class_loader, + jclass classClass, jmethodID methodForName ); + inline ~JNI_info() {} +}; + +//______________________________________________________________________________ +inline void JNI_info::destroy( JNIEnv * jni_env ) +{ + destruct( jni_env ); + delete this; +} + +//______________________________________________________________________________ +inline void JNI_info::append_sig( + ::rtl::OStringBuffer * buf, typelib_TypeDescriptionReference * type, + bool use_Object_for_type_XInterface, bool use_slashes ) +{ + switch (type->eTypeClass) + { + case typelib_TypeClass_VOID: + buf->append( 'V' ); + break; + case typelib_TypeClass_CHAR: + buf->append( 'C' ); + break; + case typelib_TypeClass_BOOLEAN: + buf->append( 'Z' ); + break; + case typelib_TypeClass_BYTE: + buf->append( 'B' ); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + buf->append( 'S' ); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + buf->append( 'I' ); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + buf->append( 'J' ); + break; + case typelib_TypeClass_FLOAT: + buf->append( 'F' ); + break; + case typelib_TypeClass_DOUBLE: + buf->append( 'D' ); + break; + case typelib_TypeClass_STRING: + if ( use_slashes ) { + buf->append( RTL_CONSTASCII_STRINGPARAM("Ljava/lang/String;") ); + } else { + buf->append( RTL_CONSTASCII_STRINGPARAM("Ljava.lang.String;") ); + } + break; + case typelib_TypeClass_TYPE: + if ( use_slashes ) { + buf->append( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/Type;") ); + } else { + buf->append( + RTL_CONSTASCII_STRINGPARAM("Lcom.sun.star.uno.Type;") ); + } + break; + case typelib_TypeClass_ANY: + if ( use_slashes ) { + buf->append( RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;") ); + } else { + buf->append( RTL_CONSTASCII_STRINGPARAM("Ljava.lang.Object;") ); + } + break; + case typelib_TypeClass_ENUM: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + ::rtl::OUString const & uno_name = + ::rtl::OUString::unacquired( &type->pTypeName ); + buf->append( 'L' ); + // Erase type arguments of instantiated polymorphic struct types: + sal_Int32 i = uno_name.indexOf( '<' ); + if ( i < 0 ) { + buf->append( + ::rtl::OUStringToOString( + use_slashes ? uno_name.replace( '.', '/' ) : uno_name, + RTL_TEXTENCODING_JAVA_UTF8 ) ); + } else { + rtl::OUString s( uno_name.copy( 0, i ) ); + buf->append( + ::rtl::OUStringToOString( + use_slashes ? s.replace( '.', '/' ) : s, + RTL_TEXTENCODING_JAVA_UTF8 ) ); + } + buf->append( ';' ); + break; + } + case typelib_TypeClass_SEQUENCE: + { + buf->append( '[' ); + TypeDescr td( type ); + append_sig( + buf, ((typelib_IndirectTypeDescription *)td.get())->pType, + use_Object_for_type_XInterface, use_slashes ); + break; + } + case typelib_TypeClass_INTERFACE: + if (use_Object_for_type_XInterface && is_XInterface( type )) + { + if ( use_slashes ) { + buf->append( RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;") ); + } else { + buf->append( RTL_CONSTASCII_STRINGPARAM("Ljava.lang.Object;") ); + } + } + else + { + ::rtl::OUString const & uno_name = + ::rtl::OUString::unacquired( &type->pTypeName ); + buf->append( 'L' ); + buf->append( + ::rtl::OUStringToOString( + use_slashes ? uno_name.replace( '.', '/' ) : uno_name, + RTL_TEXTENCODING_JAVA_UTF8 ) ); + buf->append( ';' ); + } + break; + default: + throw BridgeRuntimeError( + OUSTR("unsupported type: ") + + ::rtl::OUString::unacquired( &type->pTypeName ) ); + } +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/jni_uno/jni_java2uno.cxx b/bridges/source/jni_uno/jni_java2uno.cxx new file mode 100644 index 000000000000..63a9c0ad02ac --- /dev/null +++ b/bridges/source/jni_uno/jni_java2uno.cxx @@ -0,0 +1,706 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 <sal/alloca.h> + +#include "jni_bridge.h" + +#include <rtl/ustrbuf.hxx> + +#include <algorithm> + + +using namespace ::rtl; + +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 = 0; + (*m_uno_env->getObjectIdentifier)( m_uno_env, &pOid, pUnoI ); + OSL_ASSERT( 0 != pOid ); + 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( + m_jni_info->m_object_java_env, + m_jni_info->m_method_IEnvironment_getRegisteredInterface, args ); + jni.ensure_no_exception(); + + if (0 == jo_iface) // no registered iface + { + // register uno interface + (*m_uno_env->registerInterface)( + m_uno_env, reinterpret_cast< void ** >( &pUnoI ), + oid.pData, (typelib_InterfaceTypeDescription *)info->m_td.get() ); + + // create java and register java proxy + jvalue args2[ 7 ]; + acquire(); + args2[ 0 ].j = reinterpret_cast< sal_Int64 >( this ); + (*pUnoI->acquire)( pUnoI ); + args2[ 1 ].l = m_jni_info->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; + jo_iface = jni->CallStaticObjectMethodA( + m_jni_info->m_class_JNI_proxy, + m_jni_info->m_method_JNI_proxy_create, args2 ); + jni.ensure_no_exception(); + } + + OSL_ASSERT( 0 != jo_iface ); + return jo_iface; +} + + +//______________________________________________________________________________ +void Bridge::handle_uno_exc( JNI_context const & jni, uno_Any * uno_exc ) const +{ + if (typelib_TypeClass_EXCEPTION == uno_exc->pType->eTypeClass) + { +#if OSL_DEBUG_LEVEL > 0 + // append java stack trace to Message member + reinterpret_cast< ::com::sun::star::uno::Exception * >( + uno_exc->pData )->Message += jni.get_stack_trace(); +#endif + +#if OSL_DEBUG_LEVEL > 1 + { + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("exception occurred java->uno: [") ); + buf.append( OUString::unacquired( &uno_exc->pType->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] ") ); + buf.append( + reinterpret_cast< ::com::sun::star::uno::Exception const * >( + uno_exc->pData )->Message ); + OString cstr_msg( + OUStringToOString( + buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( "%s", cstr_msg.getStr() ); + } +#endif + // signal exception + jvalue java_exc; + try + { + map_to_java( + jni, &java_exc, uno_exc->pData, uno_exc->pType, 0, + true /* in */, false /* no out */ ); + } + catch (...) + { + uno_any_destruct( uno_exc, 0 ); + throw; + } + uno_any_destruct( uno_exc, 0 ); + + JLocalAutoRef jo_exc( jni, java_exc.l ); + jint res = jni->Throw( (jthrowable) jo_exc.get() ); + if (0 != res) + { + // call toString() + JLocalAutoRef jo_descr( + jni, jni->CallObjectMethodA( + jo_exc.get(), m_jni_info->m_method_Object_toString, 0 ) ); + jni.ensure_no_exception(); + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "throwing java exception failed: ") ); + buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + } + else + { + OUString message( + OUSTR("thrown exception is no uno exception: ") + + OUString::unacquired( &uno_exc->pType->pTypeName ) + + jni.get_stack_trace() ); + uno_any_destruct( uno_exc, 0 ); + throw BridgeRuntimeError( message ); + } +} + +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; + } + +#ifdef BROKEN_ALLOCA + char * mem = (char *) malloc( +#else + char * mem = (char *) alloca( +#endif + (nParams * sizeof (void *)) + + return_size + (nParams * sizeof (largest)) ); + void ** uno_args = (void **) mem; + void * uno_ret = return_size == 0 ? 0 : (mem + (nParams * sizeof (void *))); + largest * uno_args_mem = (largest *) + (mem + (nParams * sizeof (void *)) + return_size); + + OSL_ASSERT( (0 == nParams) || (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 (typelib_TypeClass_STRUCT == type->eTypeClass || + typelib_TypeClass_EXCEPTION == type->eTypeClass) + { + TypeDescr td( type ); + if (sal::static_int_cast< sal_uInt32 >(td.get()->nSize) + > sizeof (largest)) +#ifdef BROKEN_ALLOCA + uno_args[ nPos ] = malloc( td.get()->nSize ); +#else + uno_args[ nPos ] = alloca( td.get()->nSize ); +#endif + } + + 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, 0, + false /* no assign */, sal_False != 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, 0 ); + } +#ifdef BROKEN_ALLOCA + if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ]) + free( uno_args[ nPos ] ); +#endif + } +#ifdef BROKEN_ALLOCA + free( mem ); +#endif + 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 (0 == uno_exc) + { + // 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, 0, + 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, 0 ); +#ifdef BROKEN_ALLOCA + if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ]) + free( uno_args[ nPos ] ); +#endif + } + // cleanup uno return value + uno_type_destructData( uno_ret, return_type, 0 ); +#ifdef BROKEN_ALLOCA + free( mem ); +#endif + throw; + } + } + if (typelib_TypeClass_DOUBLE < type->eTypeClass && + typelib_TypeClass_ENUM != type->eTypeClass) // opt + { + uno_type_destructData( uno_args[ nPos ], type, 0 ); +#ifdef BROKEN_ALLOCA + if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ]) + free( uno_args[ nPos ] ); +#endif + } + } + + if (typelib_TypeClass_VOID != return_type->eTypeClass) + { + // convert uno return value + jvalue java_ret; + try + { + map_to_java( + jni, &java_ret, uno_ret, return_type, 0, + true /* in */, false /* no out */, + true /* special_wrapped_integral_types */ ); + } + catch (...) + { + uno_type_destructData( uno_ret, return_type, 0 ); +#ifdef BROKEN_ALLOCA + free( mem ); +#endif + throw; + } + if (typelib_TypeClass_DOUBLE < return_type->eTypeClass && + typelib_TypeClass_ENUM != return_type->eTypeClass) // opt + { + uno_type_destructData( uno_ret, return_type, 0 ); + } +#ifdef BROKEN_ALLOCA + free( mem ); +#endif + return java_ret.l; + } +#ifdef BROKEN_ALLOCA + free( mem ); +#endif + return 0; // 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, 0 ); +#ifdef BROKEN_ALLOCA + if (uno_args[ nPos ] && uno_args[ nPos ] != &uno_args_mem[ nPos ]) + free( uno_args[ nPos ] ); +#endif + } + + handle_uno_exc( jni, uno_exc ); +#ifdef BROKEN_ALLOCA + free( mem ); +#endif + return 0; + } +} + +} + +using namespace ::jni_uno; + +extern "C" +{ + +//------------------------------------------------------------------------------ +JNIEXPORT jobject +JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call( + JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle, jstring, + jstring jo_method, jobjectArray jo_args /* may be 0 */ ) + SAL_THROW_EXTERN_C() +{ + Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle ); + JNI_info const * jni_info = bridge->m_jni_info; + JNI_context jni( + jni_info, jni_env, + static_cast< jobject >( + reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( + bridge->m_java_env->pContext )->getClassLoader() ) ); + + OUString method_name; + + try + { + method_name = jstring_to_oustring( jni, jo_method ); +#if OSL_DEBUG_LEVEL > 1 + { + OUStringBuffer trace_buf( 64 ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("java->uno call: ") ); + trace_buf.append( method_name ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" on oid ") ); + JLocalAutoRef jo_oid( + jni, jni->GetObjectField( + jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) ); + trace_buf.append( jstring_to_oustring( jni, (jstring) jo_oid.get() ) ); + OString cstr_msg( + OUStringToOString( + trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( "%s", cstr_msg.getStr() ); + } +#endif + + // special IQueryInterface.queryInterface() + if (method_name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("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( + OUSTR("incomplete type object: no type name!") + + jni.get_stack_trace() ); + } + OUString type_name( + jstring_to_oustring( jni, (jstring) jo_type_name.get() ) ); + JNI_type_info const * info = + jni_info->get_type_info( jni, type_name ); + if (typelib_TypeClass_INTERFACE != info->m_td.get()->eTypeClass) + { + throw BridgeRuntimeError( + OUSTR("queryInterface() call demands an INTERFACE type!") ); + } + 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 (0 == uno_exc) + { + jobject jo_ret = 0; + if (typelib_TypeClass_INTERFACE == uno_ret.pType->eTypeClass) + { + uno_Interface * pUnoRet = + (uno_Interface *) uno_ret.pReserved; + if (0 != pUnoRet) + { + try + { + jo_ret = + bridge->map_to_java( jni, pUnoRet, iface_info ); + } + catch (...) + { + uno_any_destruct( &uno_ret, 0 ); + throw; + } + } + } + uno_any_destruct( &uno_ret, 0 ); + return jo_ret; + } + else + { + bridge->handle_uno_exc( jni, uno_exc ); + return 0; + } + } + + 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; + OSL_ASSERT( + offset >= 2 && offset < type_name.getLength() + && type_name[offset - 1] == ':' ); + sal_Int32 remainder = type_name.getLength() - offset; + if (typelib_TypeClass_INTERFACE_METHOD == member_type->eTypeClass) + { + 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 + { + OSL_ASSERT( + typelib_TypeClass_INTERFACE_ATTRIBUTE == + member_type->eTypeClass ); + + 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 ('g' == method_name[ 0 ]) + { + 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, 0, + jo_args ); + } + else if ('s' == method_name[ 0 ]) + { + 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 = sal_True; + param.bOut = sal_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! + OUStringBuffer buf( 64 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "calling undeclared function on interface ") ); + buf.append( OUString::unacquired( + &((typelib_TypeDescription *)td)->pTypeName ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") ); + buf.append( method_name ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + catch (BridgeRuntimeError & err) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("[jni_uno bridge error] " + "Java calling UNO method ") ); + buf.append( method_name ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") ); + buf.append( err.m_message ); + // notify RuntimeException + OString cstr_msg( + OUStringToOString( + buf.makeStringAndClear(), RTL_TEXTENCODING_JAVA_UTF8 ) ); + OSL_FAIL( cstr_msg.getStr() ); + if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr()) + != 0) + { + OSL_ASSERT( false ); + } + return 0; + } + catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) + { + OString cstr_msg( + OString( RTL_CONSTASCII_STRINGPARAM( + "[jni_uno bridge error] " + "attaching current thread to java failed!") ) + + OUStringToOString( + jni.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8 ) ); + OSL_FAIL( cstr_msg.getStr() ); + if (jni->ThrowNew(jni_info->m_class_RuntimeException, cstr_msg.getStr()) + != 0) + { + OSL_ASSERT( false ); + } + return 0; + } +} + +//------------------------------------------------------------------------------ +JNIEXPORT void +JNICALL Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J( + JNIEnv * jni_env, jobject jo_proxy, jlong bridge_handle ) + SAL_THROW_EXTERN_C() +{ + Bridge const * bridge = reinterpret_cast< Bridge const * >( bridge_handle ); + JNI_info const * jni_info = bridge->m_jni_info; + JNI_context jni( + jni_info, jni_env, + static_cast< jobject >( + reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( + bridge->m_java_env->pContext )->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 ) ); + +#if OSL_DEBUG_LEVEL > 1 + { + JLocalAutoRef jo_oid( + jni, jni->GetObjectField( + jo_proxy, jni_info->m_field_JNI_proxy_m_oid ) ); + OUString oid( jstring_to_oustring( jni, (jstring) jo_oid.get() ) ); + OString cstr_msg( + OUStringToOString( + OUSTR("freeing java uno proxy: ") + oid, + RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( "%s", cstr_msg.getStr() ); + } +#endif + // 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: */ diff --git a/bridges/source/jni_uno/jni_uno2java.cxx b/bridges/source/jni_uno/jni_uno2java.cxx new file mode 100644 index 000000000000..5fa8fa3e01b3 --- /dev/null +++ b/bridges/source/jni_uno/jni_uno2java.cxx @@ -0,0 +1,875 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 <sal/alloca.h> + +#include "com/sun/star/uno/RuntimeException.hpp" + +#include "rtl/ustrbuf.hxx" + +#include "jni_bridge.h" + + +using namespace ::std; +using namespace ::rtl; + +namespace +{ +extern "C" +{ + +//------------------------------------------------------------------------------ +void SAL_CALL UNO_proxy_free( uno_ExtEnvironment * env, void * proxy ) + SAL_THROW_EXTERN_C(); + +//------------------------------------------------------------------------------ +void SAL_CALL UNO_proxy_acquire( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C(); + +//------------------------------------------------------------------------------ +void SAL_CALL UNO_proxy_release( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C(); + +//------------------------------------------------------------------------------ +void SAL_CALL UNO_proxy_dispatch( + uno_Interface * pUnoI, typelib_TypeDescription const * member_td, + void * uno_ret, void * uno_args[], uno_Any ** uno_exc ) + SAL_THROW_EXTERN_C(); +} +} + +namespace jni_uno +{ + +//______________________________________________________________________________ +void Bridge::handle_java_exc( + JNI_context const & jni, + JLocalAutoRef const & jo_exc, uno_Any * uno_exc ) const +{ + OSL_ASSERT( jo_exc.is() ); + if (! jo_exc.is()) + { + throw BridgeRuntimeError( + OUSTR("java exception occurred, but no java exception available!?") + + jni.get_stack_trace() ); + } + + JLocalAutoRef jo_class( jni, jni->GetObjectClass( jo_exc.get() ) ); + JLocalAutoRef jo_class_name( + jni, jni->CallObjectMethodA( + jo_class.get(), m_jni_info->m_method_Class_getName, 0 ) ); + jni.ensure_no_exception(); + OUString exc_name( + jstring_to_oustring( jni, (jstring) jo_class_name.get() ) ); + + ::com::sun::star::uno::TypeDescription td( exc_name.pData ); + if (!td.is() || (typelib_TypeClass_EXCEPTION != td.get()->eTypeClass)) + { + // call toString() + JLocalAutoRef jo_descr( + jni, jni->CallObjectMethodA( + jo_exc.get(), m_jni_info->m_method_Object_toString, 0 ) ); + jni.ensure_no_exception(); + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("non-UNO exception occurred: ") ); + buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) ); + buf.append( jni.get_stack_trace( jo_exc.get() ) ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + + auto_ptr< rtl_mem > uno_data( rtl_mem::allocate( td.get()->nSize ) ); + jvalue val; + val.l = jo_exc.get(); + map_to_uno( + jni, uno_data.get(), val, td.get()->pWeakRef, 0, + false /* no assign */, false /* no out param */ ); + +#if OSL_DEBUG_LEVEL > 0 + // patch Message, append stack trace + reinterpret_cast< ::com::sun::star::uno::Exception * >( + uno_data.get() )->Message += jni.get_stack_trace( jo_exc.get() ); +#endif + + typelib_typedescriptionreference_acquire( td.get()->pWeakRef ); + uno_exc->pType = td.get()->pWeakRef; + uno_exc->pData = uno_data.release(); + +#if OSL_DEBUG_LEVEL > 1 + OUStringBuffer trace_buf( 128 ); + trace_buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("exception occurred uno->java: [") ); + trace_buf.append( exc_name ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] ") ); + trace_buf.append( + reinterpret_cast< ::com::sun::star::uno::Exception const * >( + uno_exc->pData )->Message ); + OString cstr_trace( + OUStringToOString( + trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( "%s", cstr_trace.getStr() ); +#endif +} + +//______________________________________________________________________________ +void Bridge::call_java( + jobject javaI, typelib_InterfaceTypeDescription * iface_td, + sal_Int32 local_member_index, sal_Int32 function_pos_offset, + typelib_TypeDescriptionReference * return_type, + typelib_MethodParameter * params, sal_Int32 nParams, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) const +{ + OSL_ASSERT( function_pos_offset == 0 || function_pos_offset == 1 ); + + JNI_guarded_context jni( + m_jni_info, reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( + m_java_env->pContext ) ); + + // assure fully initialized iface_td: + ::com::sun::star::uno::TypeDescription iface_holder; + if (! iface_td->aBase.bComplete) { + iface_holder = ::com::sun::star::uno::TypeDescription( + reinterpret_cast<typelib_TypeDescription *>(iface_td) ); + iface_holder.makeComplete(); + if (! iface_holder.get()->bComplete) { + OUStringBuffer buf; + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM("cannot make type complete: ") ); + buf.append( OUString::unacquired(&iface_holder.get()->pTypeName) ); + buf.append( jni.get_stack_trace() ); + throw BridgeRuntimeError( buf.makeStringAndClear() ); + } + iface_td = reinterpret_cast<typelib_InterfaceTypeDescription *>( + iface_holder.get() ); + OSL_ASSERT( iface_td->aBase.eTypeClass == typelib_TypeClass_INTERFACE ); + } + + // prepare java args, save param td +#ifdef BROKEN_ALLOCA + jvalue * java_args = (jvalue *) malloc( sizeof (jvalue) * nParams ); +#else + jvalue * java_args = (jvalue *) alloca( sizeof (jvalue) * nParams ); +#endif + + sal_Int32 nPos; + for ( nPos = 0; nPos < nParams; ++nPos ) + { + try + { + typelib_MethodParameter const & param = params[ nPos ]; + java_args[ nPos ].l = 0; // if out: build up array[ 1 ] + map_to_java( + jni, &java_args[ nPos ], + uno_args[ nPos ], + param.pTypeRef, 0, + sal_False != param.bIn /* convert uno value */, + sal_False != param.bOut /* build up array[ 1 ] */ ); + } + catch (...) + { + // cleanup + for ( sal_Int32 n = 0; n < nPos; ++n ) + { + typelib_MethodParameter const & param = params[ n ]; + if (param.bOut || + typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass) + { + jni->DeleteLocalRef( java_args[ n ].l ); + } + } +#ifdef BROKEN_ALLOCA + free( java_args ); +#endif + throw; + } + } + + sal_Int32 base_members = iface_td->nAllMembers - iface_td->nMembers; + OSL_ASSERT( base_members < iface_td->nAllMembers ); + sal_Int32 base_members_function_pos = + iface_td->pMapMemberIndexToFunctionIndex[ base_members ]; + sal_Int32 member_pos = base_members + local_member_index; + OSL_ENSURE( + member_pos < iface_td->nAllMembers, "### member pos out of range!" ); + sal_Int32 function_pos = + iface_td->pMapMemberIndexToFunctionIndex[ member_pos ] + + function_pos_offset; + OSL_ENSURE( + function_pos >= base_members_function_pos + && function_pos < iface_td->nMapFunctionIndexToMemberIndex, + "### illegal function index!" ); + function_pos -= base_members_function_pos; + + JNI_interface_type_info const * info = + static_cast< JNI_interface_type_info const * >( + m_jni_info->get_type_info( jni, &iface_td->aBase ) ); + jmethodID method_id = info->m_methods[ function_pos ]; + +#if OSL_DEBUG_LEVEL > 1 + OUStringBuffer trace_buf( 128 ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("calling ") ); + JLocalAutoRef jo_method( + jni, jni->ToReflectedMethod( info->m_class, method_id, JNI_FALSE ) ); + jni.ensure_no_exception(); + JLocalAutoRef jo_descr( + jni, jni->CallObjectMethodA( + jo_method.get(), m_jni_info->m_method_Object_toString, 0 ) ); + jni.ensure_no_exception(); + trace_buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" on ") ); + jo_descr.reset( + jni->CallObjectMethodA( + javaI, m_jni_info->m_method_Object_toString, 0 ) ); + jni.ensure_no_exception(); + trace_buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" (") ); + JLocalAutoRef jo_class( jni, jni->GetObjectClass( javaI ) ); + jo_descr.reset( + jni->CallObjectMethodA( + jo_class.get(), m_jni_info->m_method_Object_toString, 0 ) ); + jni.ensure_no_exception(); + trace_buf.append( jstring_to_oustring( jni, (jstring) jo_descr.get() ) ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(")") ); + OString cstr_trace( + OUStringToOString( + trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( "%s", cstr_trace.getStr() ); +#endif + + // complex return value + JLocalAutoRef java_ret( jni ); + + switch (return_type->eTypeClass) + { + case typelib_TypeClass_VOID: + jni->CallVoidMethodA( javaI, method_id, java_args ); + break; + case typelib_TypeClass_CHAR: + *(sal_Unicode *)uno_ret = + jni->CallCharMethodA( javaI, method_id, java_args ); + break; + case typelib_TypeClass_BOOLEAN: + *(sal_Bool *)uno_ret = + jni->CallBooleanMethodA( javaI, method_id, java_args ); + break; + case typelib_TypeClass_BYTE: + *(sal_Int8 *)uno_ret = + jni->CallByteMethodA( javaI, method_id, java_args ); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *(sal_Int16 *)uno_ret = + jni->CallShortMethodA( javaI, method_id, java_args ); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *(sal_Int32 *)uno_ret = + jni->CallIntMethodA( javaI, method_id, java_args ); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *(sal_Int64 *)uno_ret = + jni->CallLongMethodA( javaI, method_id, java_args ); + break; + case typelib_TypeClass_FLOAT: + *(float *)uno_ret = + jni->CallFloatMethodA( javaI, method_id, java_args ); + break; + case typelib_TypeClass_DOUBLE: + *(double *)uno_ret = + jni->CallDoubleMethodA( javaI, method_id, java_args ); + break; + default: + java_ret.reset( + jni->CallObjectMethodA( javaI, method_id, java_args ) ); + break; + } + + if (jni->ExceptionCheck()) + { + JLocalAutoRef jo_exc( jni, jni->ExceptionOccurred() ); + jni->ExceptionClear(); + + // release temp java local refs + for ( nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = params[ nPos ]; + if (param.bOut || + typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass) + { + jni->DeleteLocalRef( java_args[ nPos ].l ); + } + } + + handle_java_exc( jni, jo_exc, *uno_exc ); + } + else // no exception + { + for ( nPos = 0; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & param = params[ nPos ]; + if (param.bOut) + { + try + { + map_to_uno( + jni, uno_args[ nPos ], + java_args[ nPos ], param.pTypeRef, 0, + sal_False != param.bIn /* assign if inout */, + true /* out param */ ); + } + catch (...) + { + // cleanup uno pure out + for ( sal_Int32 n = 0; n < nPos; ++n ) + { + typelib_MethodParameter const & p = params[ n ]; + if (! p.bIn) + { + uno_type_destructData( + uno_args[ n ], p.pTypeRef, 0 ); + } + } + // cleanup java temp local refs + for ( ; nPos < nParams; ++nPos ) + { + typelib_MethodParameter const & p = params[ nPos ]; + if (p.bOut || + typelib_TypeClass_DOUBLE < + p.pTypeRef->eTypeClass) + { + jni->DeleteLocalRef( java_args[ nPos ].l ); + } + } +#ifdef BROKEN_ALLOCA + free( java_args ); +#endif + throw; + } + jni->DeleteLocalRef( java_args[ nPos ].l ); + } + else // pure temp in param + { + if (typelib_TypeClass_DOUBLE < param.pTypeRef->eTypeClass) + jni->DeleteLocalRef( java_args[ nPos ].l ); + } + } + + // return value + if (typelib_TypeClass_DOUBLE < return_type->eTypeClass) + { + try + { + jvalue val; + val.l = java_ret.get(); + map_to_uno( + jni, uno_ret, val, return_type, 0, + false /* no assign */, false /* no out param */ ); + } + catch (...) + { + // cleanup uno pure out + for ( sal_Int32 i = 0; i < nParams; ++i ) + { + typelib_MethodParameter const & param = params[ i ]; + if (! param.bIn) + { + uno_type_destructData( + uno_args[ i ], param.pTypeRef, 0 ); + } + } +#ifdef BROKEN_ALLOCA + free( java_args ); +#endif + throw; + } + } // else: already set integral uno return value + + // no exception occurred + *uno_exc = 0; + } +#ifdef BROKEN_ALLOCA + free( java_args ); +#endif +} + +//==== a uno proxy wrapping a java interface =================================== +struct UNO_proxy : public uno_Interface +{ + mutable oslInterlockedCount m_ref; + Bridge const * m_bridge; + + // mapping information + jobject m_javaI; + jstring m_jo_oid; + OUString m_oid; + JNI_interface_type_info const * m_type_info; + + inline void acquire() const; + inline void release() const; + + // ctor + inline UNO_proxy( + JNI_context const & jni, Bridge const * bridge, + jobject javaI, jstring jo_oid, OUString const & oid, + JNI_interface_type_info const * info ); +}; + +//______________________________________________________________________________ +inline UNO_proxy::UNO_proxy( + JNI_context const & jni, Bridge const * bridge, + jobject javaI, jstring jo_oid, OUString const & oid, + JNI_interface_type_info const * info ) + : m_ref( 1 ), + m_oid( oid ), + m_type_info( info ) +{ + JNI_info const * jni_info = bridge->m_jni_info; + JLocalAutoRef jo_string_array( + jni, jni->NewObjectArray( 1, jni_info->m_class_String, jo_oid ) ); + jni.ensure_no_exception(); + jvalue args[ 3 ]; + args[ 0 ].l = javaI; + args[ 1 ].l = jo_string_array.get(); + args[ 2 ].l = info->m_type; + jobject jo_iface = jni->CallObjectMethodA( + jni_info->m_object_java_env, + jni_info->m_method_IEnvironment_registerInterface, args ); + jni.ensure_no_exception(); + + m_javaI = jni->NewGlobalRef( jo_iface ); + m_jo_oid = (jstring) jni->NewGlobalRef( jo_oid ); + bridge->acquire(); + m_bridge = bridge; + + // uno_Interface + uno_Interface::acquire = UNO_proxy_acquire; + uno_Interface::release = UNO_proxy_release; + uno_Interface::pDispatcher = UNO_proxy_dispatch; +} + +//______________________________________________________________________________ +inline void UNO_proxy::acquire() const +{ + if (1 == osl_incrementInterlockedCount( &m_ref )) + { + // rebirth of proxy zombie + void * that = const_cast< UNO_proxy * >( this ); + // register at uno env + (*m_bridge->m_uno_env->registerProxyInterface)( + m_bridge->m_uno_env, &that, + UNO_proxy_free, m_oid.pData, + (typelib_InterfaceTypeDescription *)m_type_info->m_td.get() ); +#if OSL_DEBUG_LEVEL > 1 + OSL_ASSERT( this == (void const * const)that ); +#endif + } +} + +//______________________________________________________________________________ +inline void UNO_proxy::release() const +{ + if (0 == osl_decrementInterlockedCount( &m_ref )) + { + // revoke from uno env on last release + (*m_bridge->m_uno_env->revokeInterface)( + m_bridge->m_uno_env, const_cast< UNO_proxy * >( this ) ); + } +} + + +//______________________________________________________________________________ +uno_Interface * Bridge::map_to_uno( + JNI_context const & jni, + jobject javaI, JNI_interface_type_info const * info ) const +{ + JLocalAutoRef jo_oid( jni, compute_oid( jni, javaI ) ); + OUString oid( jstring_to_oustring( jni, (jstring) jo_oid.get() ) ); + + uno_Interface * pUnoI = 0; + (*m_uno_env->getRegisteredInterface)( + m_uno_env, (void **)&pUnoI, + oid.pData, (typelib_InterfaceTypeDescription *)info->m_td.get() ); + + if (0 == pUnoI) // no existing interface, register new proxy + { + // refcount initially 1 + pUnoI = new UNO_proxy( + jni, const_cast< Bridge * >( this ), + javaI, (jstring) jo_oid.get(), oid, info ); + + (*m_uno_env->registerProxyInterface)( + m_uno_env, (void **)&pUnoI, + UNO_proxy_free, + oid.pData, (typelib_InterfaceTypeDescription *)info->m_td.get() ); + } + return pUnoI; +} + +} + +using namespace ::jni_uno; + +namespace +{ +extern "C" +{ + +//------------------------------------------------------------------------------ +void SAL_CALL UNO_proxy_free( uno_ExtEnvironment * env, void * proxy ) + SAL_THROW_EXTERN_C() +{ + UNO_proxy const * that = reinterpret_cast< UNO_proxy const * >( proxy ); + Bridge const * bridge = that->m_bridge; + + if ( env != bridge->m_uno_env ) { + OSL_ASSERT(false); + } +#if OSL_DEBUG_LEVEL > 1 + OString cstr_msg( + OUStringToOString( + OUSTR("freeing binary uno proxy: ") + that->m_oid, + RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( "%s", cstr_msg.getStr() ); +#endif + + try + { + JNI_guarded_context jni( + bridge->m_jni_info, + reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( + bridge->m_java_env->pContext ) ); + + jni->DeleteGlobalRef( that->m_javaI ); + jni->DeleteGlobalRef( that->m_jo_oid ); + } + catch (BridgeRuntimeError & err) + { +#if OSL_DEBUG_LEVEL > 0 + OString cstr_msg2( + OUStringToOString( err.m_message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_FAIL( cstr_msg2.getStr() ); +#else + (void) err; // unused +#endif + } + catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) + { + OSL_FAIL( + "[jni_uno bridge error] attaching current thread to java failed!" ); + } + + bridge->release(); +#if OSL_DEBUG_LEVEL > 1 + *(int *)that = 0xdeadcafe; +#endif + delete that; +} + +//------------------------------------------------------------------------------ +void SAL_CALL UNO_proxy_acquire( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C() +{ + UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI ); + that->acquire(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL UNO_proxy_release( uno_Interface * pUnoI ) + SAL_THROW_EXTERN_C() +{ + UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI ); + that->release(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL UNO_proxy_dispatch( + uno_Interface * pUnoI, typelib_TypeDescription const * member_td, + void * uno_ret, void * uno_args [], uno_Any ** uno_exc ) + SAL_THROW_EXTERN_C() +{ + UNO_proxy const * that = static_cast< UNO_proxy const * >( pUnoI ); + Bridge const * bridge = that->m_bridge; + +#if OSL_DEBUG_LEVEL > 1 + OUStringBuffer trace_buf( 64 ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("uno->java call: ") ); + trace_buf.append( OUString::unacquired( &member_td->pTypeName ) ); + trace_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" on oid ") ); + trace_buf.append( that->m_oid ); + OString cstr_msg( + OUStringToOString( + trace_buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( "%s", cstr_msg.getStr() ); +#endif + + try + { + switch (member_td->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_InterfaceAttributeTypeDescription const * attrib_td = + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription const * >( + member_td ); + com::sun::star::uno::TypeDescription attrib_holder; + while ( attrib_td->pBaseRef != 0 ) { + attrib_holder = com::sun::star::uno::TypeDescription( + attrib_td->pBaseRef ); + OSL_ASSERT( + attrib_holder.get()->eTypeClass + == typelib_TypeClass_INTERFACE_ATTRIBUTE ); + attrib_td = reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + attrib_holder.get() ); + } + typelib_InterfaceTypeDescription * iface_td = attrib_td->pInterface; + + if (0 == uno_ret) // is setter method + { + typelib_MethodParameter param; + param.pTypeRef = attrib_td->pAttributeTypeRef; + param.bIn = sal_True; + param.bOut = sal_False; + + bridge->call_java( + that->m_javaI, iface_td, + attrib_td->nIndex, 1, // get, then set method + bridge->m_jni_info->m_void_type.getTypeLibType(), + ¶m, 1, + 0, uno_args, uno_exc ); + } + else // is getter method + { + bridge->call_java( + that->m_javaI, iface_td, attrib_td->nIndex, 0, + attrib_td->pAttributeTypeRef, + 0, 0, // no params + uno_ret, 0, uno_exc ); + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription const * method_td = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription const * >( + member_td ); + com::sun::star::uno::TypeDescription method_holder; + while ( method_td->pBaseRef != 0 ) { + method_holder = com::sun::star::uno::TypeDescription( + method_td->pBaseRef ); + OSL_ASSERT( + method_holder.get()->eTypeClass + == typelib_TypeClass_INTERFACE_METHOD ); + method_td = reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + method_holder.get() ); + } + typelib_InterfaceTypeDescription * iface_td = method_td->pInterface; + + switch ( method_td->aBase.nPosition ) + { + case 0: // queryInterface() + { + TypeDescr demanded_td( + *reinterpret_cast< typelib_TypeDescriptionReference ** >( + uno_args[ 0 ] ) ); + if (typelib_TypeClass_INTERFACE != + demanded_td.get()->eTypeClass) + { + throw BridgeRuntimeError( + OUSTR("queryInterface() call demands " + "an INTERFACE type!") ); + } + + uno_Interface * pInterface = 0; + (*bridge->m_uno_env->getRegisteredInterface)( + bridge->m_uno_env, + (void **) &pInterface, that->m_oid.pData, + (typelib_InterfaceTypeDescription *)demanded_td.get() ); + + if (0 == pInterface) + { + JNI_info const * jni_info = bridge->m_jni_info; + JNI_guarded_context jni( + jni_info, + reinterpret_cast< ::jvmaccess::UnoVirtualMachine * >( + bridge->m_java_env->pContext ) ); + + JNI_interface_type_info const * info = + static_cast< JNI_interface_type_info const * >( + jni_info->get_type_info( jni, demanded_td.get() ) ); + + jvalue args[ 2 ]; + args[ 0 ].l = info->m_type; + args[ 1 ].l = that->m_javaI; + + JLocalAutoRef jo_ret( + jni, jni->CallStaticObjectMethodA( + jni_info->m_class_UnoRuntime, + jni_info->m_method_UnoRuntime_queryInterface, + args ) ); + + if (jni->ExceptionCheck()) + { + JLocalAutoRef jo_exc( jni, jni->ExceptionOccurred() ); + jni->ExceptionClear(); + bridge->handle_java_exc( jni, jo_exc, *uno_exc ); + } + else + { + if (jo_ret.is()) + { +#if OSL_DEBUG_LEVEL > 0 + JLocalAutoRef jo_oid( + jni, compute_oid( jni, jo_ret.get() ) ); + OUString oid( jstring_to_oustring( + jni, (jstring) jo_oid.get() ) ); + OSL_ENSURE( + oid.equals( that->m_oid ), + "### different oids!" ); +#endif + // refcount initially 1 + uno_Interface * pUnoI2 = new UNO_proxy( + jni, bridge, jo_ret.get(), + that->m_jo_oid, that->m_oid, info ); + + (*bridge->m_uno_env->registerProxyInterface)( + bridge->m_uno_env, + (void **) &pUnoI2, + UNO_proxy_free, that->m_oid.pData, + reinterpret_cast< + typelib_InterfaceTypeDescription * >( + info->m_td.get() ) ); + + uno_any_construct( + (uno_Any *)uno_ret, &pUnoI2, + demanded_td.get(), 0 ); + (*pUnoI2->release)( pUnoI2 ); + } + else // object does not support demanded interface + { + uno_any_construct( + reinterpret_cast< uno_Any * >( uno_ret ), + 0, 0, 0 ); + } + // no exception occurred + *uno_exc = 0; + } + } + else + { + uno_any_construct( + reinterpret_cast< uno_Any * >( uno_ret ), + &pInterface, demanded_td.get(), 0 ); + (*pInterface->release)( pInterface ); + *uno_exc = 0; + } + break; + } + case 1: // acquire this proxy + that->acquire(); + *uno_exc = 0; + break; + case 2: // release this proxy + that->release(); + *uno_exc = 0; + break; + default: // arbitrary method call + bridge->call_java( + that->m_javaI, iface_td, method_td->nIndex, 0, + method_td->pReturnTypeRef, + method_td->pParams, method_td->nParams, + uno_ret, uno_args, uno_exc ); + break; + } + break; + } + default: + { + throw BridgeRuntimeError( + OUSTR("illegal member type description!") ); + } + } + } + catch (BridgeRuntimeError & err) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM( + "[jni_uno bridge error] UNO calling Java method ") ); + if (typelib_TypeClass_INTERFACE_METHOD == member_td->eTypeClass || + typelib_TypeClass_INTERFACE_ATTRIBUTE == member_td->eTypeClass) + { + buf.append( OUString::unacquired( + &reinterpret_cast< + typelib_InterfaceMemberTypeDescription const * >( + member_td )->pMemberName ) ); + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") ); + buf.append( err.m_message ); + // binary identical struct + ::com::sun::star::uno::RuntimeException exc( + buf.makeStringAndClear(), + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XInterface >() ); + ::com::sun::star::uno::Type const & exc_type = ::getCppuType( &exc ); + uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0 ); +#if OSL_DEBUG_LEVEL > 0 + OString cstr_msg2( + OUStringToOString( exc.Message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( "%s", cstr_msg2.getStr() ); +#endif + } + catch (::jvmaccess::VirtualMachine::AttachGuard::CreationException &) + { + // binary identical struct + ::com::sun::star::uno::RuntimeException exc( + OUSTR("[jni_uno bridge error] attaching current thread " + "to java failed!"), + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XInterface >() ); + ::com::sun::star::uno::Type const & exc_type = ::getCppuType( &exc ); + uno_type_any_construct( *uno_exc, &exc, exc_type.getTypeLibType(), 0 ); +#if OSL_DEBUG_LEVEL > 0 + OString cstr_msg2( + OUStringToOString( exc.Message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_FAIL( cstr_msg2.getStr() ); +#endif + } +} + +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/jni_uno/makefile.mk b/bridges/source/jni_uno/makefile.mk new file mode 100644 index 000000000000..1474a86cd741 --- /dev/null +++ b/bridges/source/jni_uno/makefile.mk @@ -0,0 +1,86 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=bridges +TARGET=java_uno +USE_DEFFILE=TRUE +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(SOLAR_JAVA)"=="" +nojava: + @echo "Not building jni-uno bridge because Java is disabled" +.ENDIF + +# --- Files -------------------------------------------------------- + +.IF "$(GUI)$(COM)" == "WNTGCC" +.IF "$(EXCEPTIONS)" == "sjlj" +CFLAGS += -DBROKEN_ALLOCA +.ENDIF +.ENDIF + +SLOFILES= \ + $(SLO)$/jni_info.obj \ + $(SLO)$/jni_data.obj \ + $(SLO)$/jni_uno2java.obj \ + $(SLO)$/jni_java2uno.obj \ + $(SLO)$/jni_bridge.obj \ + $(SLO)$/nativethreadpool.obj + +SHL1TARGET=$(TARGET) + +SHL1STDLIBS= \ + $(JVMACCESSLIB) \ + $(CPPULIB) \ + $(SALLIB) \ + $(SALHELPERLIB) + +SHL1VERSIONMAP=$(TARGET).map + +SHL1CREATEJNILIB=TRUE +SHL1IMPLIB=i$(TARGET) +SHL1LIBS=$(SLB)$/$(TARGET).lib +SHL1DEF=$(MISC)$/$(SHL1TARGET).def +DEF1NAME=$(SHL1TARGET) +SHL1RPATH=URELIB + +.IF "$(debug)" != "" +.IF "$(COM)" == "MSC" +CFLAGS += -Ob0 +.ENDIF +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/bridges/source/jni_uno/nativethreadpool.cxx b/bridges/source/jni_uno/nativethreadpool.cxx new file mode 100644 index 000000000000..9c92e89c5b07 --- /dev/null +++ b/bridges/source/jni_uno/nativethreadpool.cxx @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 "jvmaccess/virtualmachine.hxx" +#include "rtl/byteseq.h" +#include "rtl/byteseq.hxx" +#include "rtl/memory.h" +#include "rtl/ref.hxx" +#include "sal/types.h" +#include "uno/threadpool.h" + +#include "jni.h" + +#include <new> + +/* The native implementation part of + * jurt/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java. + */ + +namespace { + +struct Pool { + Pool(rtl::Reference< jvmaccess::VirtualMachine > const & theVirtualMachine, + jmethodID theExecute, uno_ThreadPool thePool): + virtualMachine(theVirtualMachine), execute(theExecute), pool(thePool) {} + + rtl::Reference< jvmaccess::VirtualMachine > virtualMachine; + jmethodID execute; + uno_ThreadPool pool; +}; + +struct Job { + Job(Pool * thePool, jobject theJob): pool(thePool), job(theJob) {} + + Pool * pool; + jobject job; +}; + +void throwOutOfMemory(JNIEnv * env) { + jclass c = env->FindClass("java/lang/OutOfMemoryError"); + if (c != 0) { + env->ThrowNew(c, ""); + } +} + +} + +extern "C" { + +static void SAL_CALL executeRequest(void * data) { + Job * job = static_cast< Job * >(data); + try { + jvmaccess::VirtualMachine::AttachGuard guard(job->pool->virtualMachine); + JNIEnv * env = guard.getEnvironment(); + // Failure of the following Job.execute Java call is ignored; if that + // call fails, it should be due to a java.lang.Error, which is not + // handled well, anyway: + env->CallObjectMethod(job->job, job->pool->execute); + env->DeleteGlobalRef(job->job); + delete job; + } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) { + //TODO: DeleteGlobalRef(job->job) + delete job; + } +} + +} + +extern "C" JNIEXPORT jbyteArray JNICALL +Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_threadId( + JNIEnv * env, jclass) SAL_THROW_EXTERN_C() +{ + sal_Sequence * s = 0; + uno_getIdOfCurrentThread(&s); //TODO: out of memory + uno_releaseIdFromCurrentThread(); + rtl::ByteSequence seq(s); + rtl_byte_sequence_release(s); + sal_Int32 n = seq.getLength(); + jbyteArray a = env->NewByteArray(n); + // sal_Int32 and jsize are compatible here + if (a == 0) { + return 0; + } + void * p = env->GetPrimitiveArrayCritical(a, 0); + if (p == 0) { + return 0; + } + rtl_copyMemory(p, seq.getConstArray(), n); + // sal_Int8 and jbyte ought to be compatible + env->ReleasePrimitiveArrayCritical(a, p, 0); + return a; +} + +extern "C" JNIEXPORT jlong JNICALL +Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_create( + JNIEnv * env, jclass) SAL_THROW_EXTERN_C() +{ + JavaVM * vm; + if (env->GetJavaVM(&vm) != JNI_OK) { //TODO: no Java exception raised? + jclass c = env->FindClass("java/lang/RuntimeException"); + if (c != 0) { + env->ThrowNew(c, "JNI GetJavaVM failed"); + } + return 0; + } + jclass c = env->FindClass("com/sun/star/lib/uno/environments/remote/Job"); + if (c == 0) { + return 0; + } + jmethodID execute = env->GetMethodID(c, "execute", "()Ljava/lang/Object;"); + if (execute == 0) { + return 0; + } + try { + return reinterpret_cast< jlong >(new Pool( + new jvmaccess::VirtualMachine(vm, env->GetVersion(), false, env), + execute, uno_threadpool_create())); + } catch (std::bad_alloc) { + throwOutOfMemory(env); + return 0; + } +} + +extern "C" JNIEXPORT void JNICALL +Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_attach( + JNIEnv *, jclass, jlong pool) SAL_THROW_EXTERN_C() +{ + uno_threadpool_attach(reinterpret_cast< Pool * >(pool)->pool); +} + +extern "C" JNIEXPORT jobject JNICALL +Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_enter( + JNIEnv * env, jclass, jlong pool) SAL_THROW_EXTERN_C() +{ + jobject job; + uno_threadpool_enter( + reinterpret_cast< Pool * >(pool)->pool, + reinterpret_cast< void ** >(&job)); + if (job == 0) { + return 0; + } + jobject ref = env->NewLocalRef(job); + env->DeleteGlobalRef(job); + return ref; +} + +extern "C" JNIEXPORT void JNICALL +Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_detach( + JNIEnv *, jclass, jlong pool) SAL_THROW_EXTERN_C() +{ + uno_threadpool_detach(reinterpret_cast< Pool * >(pool)->pool); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_putJob( + JNIEnv * env, jclass, jlong pool, jbyteArray threadId, jobject job, + jboolean request, jboolean oneWay) SAL_THROW_EXTERN_C() +{ + void * s = env->GetPrimitiveArrayCritical(threadId, 0); + if (s == 0) { + return; + } + rtl::ByteSequence seq( + static_cast< sal_Int8 * >(s), env->GetArrayLength(threadId)); + // sal_Int8 and jbyte ought to be compatible; sal_Int32 and jsize are + // compatible here + //TODO: out of memory + env->ReleasePrimitiveArrayCritical(threadId, s, JNI_ABORT); + Pool * p = reinterpret_cast< Pool * >(pool); + jobject ref = env->NewGlobalRef(job); + if (ref == 0) { + return; + } + Job * j = 0; + if (request) { + j = new(std::nothrow) Job(p, ref); + if (j == 0) { + env->DeleteGlobalRef(ref); + throwOutOfMemory(env); + return; + } + } + uno_threadpool_putJob( + p->pool, seq.getHandle(), + request ? static_cast< void * >(j) : static_cast< void * >(ref), + request ? executeRequest : 0, oneWay); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_dispose( + JNIEnv *, jclass, jlong pool) SAL_THROW_EXTERN_C() +{ + uno_threadpool_dispose(reinterpret_cast< Pool * >(pool)->pool); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_sun_star_lib_uno_environments_remote_NativeThreadPool_destroy( + JNIEnv *, jclass, jlong pool) SAL_THROW_EXTERN_C() +{ + Pool * p = reinterpret_cast< Pool * >(pool); + uno_threadpool_destroy(p->pool); + delete p; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |