1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/alloca.h>
23 #include "jni_bridge.h"
25 #include <rtl/ustrbuf.hxx>
30 using namespace ::rtl
;
35 //______________________________________________________________________________
36 jobject
Bridge::map_to_java(
37 JNI_context
const & jni
,
38 uno_Interface
* pUnoI
, JNI_interface_type_info
const * info
) const
41 rtl_uString
* pOid
= 0;
42 (*m_uno_env
->getObjectIdentifier
)( m_uno_env
, &pOid
, pUnoI
);
43 OSL_ASSERT( 0 != pOid
);
44 OUString
oid( pOid
, SAL_NO_ACQUIRE
);
46 // opt getRegisteredInterface()
47 JLocalAutoRef
jo_oid( jni
, ustring_to_jstring( jni
, oid
.pData
) );
49 args
[ 0 ].l
= jo_oid
.get();
50 args
[ 1 ].l
= info
->m_type
;
51 jobject jo_iface
= jni
->CallObjectMethodA(
52 m_jni_info
->m_object_java_env
,
53 m_jni_info
->m_method_IEnvironment_getRegisteredInterface
, args
);
54 jni
.ensure_no_exception();
56 if (0 == jo_iface
) // no registered iface
58 // register uno interface
59 (*m_uno_env
->registerInterface
)(
60 m_uno_env
, reinterpret_cast< void ** >( &pUnoI
),
61 oid
.pData
, (typelib_InterfaceTypeDescription
*)info
->m_td
.get() );
63 // create java and register java proxy
66 args2
[ 0 ].j
= reinterpret_cast< sal_Int64
>( this );
67 (*pUnoI
->acquire
)( pUnoI
);
68 args2
[ 1 ].l
= m_jni_info
->m_object_java_env
;
69 args2
[ 2 ].j
= reinterpret_cast< sal_Int64
>( pUnoI
);
70 typelib_typedescription_acquire( info
->m_td
.get() );
71 args2
[ 3 ].j
= reinterpret_cast< sal_Int64
>( info
->m_td
.get() );
72 args2
[ 4 ].l
= info
->m_type
;
73 args2
[ 5 ].l
= jo_oid
.get();
74 args2
[ 6 ].l
= info
->m_proxy_ctor
;
75 jo_iface
= jni
->CallStaticObjectMethodA(
76 m_jni_info
->m_class_JNI_proxy
,
77 m_jni_info
->m_method_JNI_proxy_create
, args2
);
78 jni
.ensure_no_exception();
81 OSL_ASSERT( 0 != jo_iface
);
86 //______________________________________________________________________________
87 void Bridge::handle_uno_exc( JNI_context
const & jni
, uno_Any
* uno_exc
) const
89 if (typelib_TypeClass_EXCEPTION
== uno_exc
->pType
->eTypeClass
)
91 #if OSL_DEBUG_LEVEL > 0
92 // append java stack trace to Message member
93 reinterpret_cast< ::com::sun::star::uno::Exception
* >(
94 uno_exc
->pData
)->Message
+= jni
.get_stack_trace();
97 #if OSL_DEBUG_LEVEL > 1
99 OUStringBuffer
buf( 128 );
100 buf
.append( "exception occurred java->uno: [" );
101 buf
.append( OUString::unacquired( &uno_exc
->pType
->pTypeName
) );
104 reinterpret_cast< ::com::sun::star::uno::Exception
const * >(
105 uno_exc
->pData
)->Message
);
108 buf
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
) );
109 OSL_TRACE( "%s", cstr_msg
.getStr() );
117 jni
, &java_exc
, uno_exc
->pData
, uno_exc
->pType
, 0,
118 true /* in */, false /* no out */ );
122 uno_any_destruct( uno_exc
, 0 );
125 uno_any_destruct( uno_exc
, 0 );
127 JLocalAutoRef
jo_exc( jni
, java_exc
.l
);
128 jint res
= jni
->Throw( (jthrowable
) jo_exc
.get() );
132 JLocalAutoRef
jo_descr(
133 jni
, jni
->CallObjectMethodA(
134 jo_exc
.get(), m_jni_info
->m_method_Object_toString
, 0 ) );
135 jni
.ensure_no_exception();
136 OUStringBuffer
buf( 128 );
137 buf
.append( "throwing java exception failed: " );
138 buf
.append( jstring_to_oustring( jni
, (jstring
) jo_descr
.get() ) );
139 buf
.append( jni
.get_stack_trace() );
140 throw BridgeRuntimeError( buf
.makeStringAndClear() );
146 "thrown exception is no uno exception: " +
147 OUString::unacquired( &uno_exc
->pType
->pTypeName
) +
148 jni
.get_stack_trace() );
149 uno_any_destruct( uno_exc
, 0 );
150 throw BridgeRuntimeError( message
);
162 //______________________________________________________________________________
163 jobject
Bridge::call_uno(
164 JNI_context
const & jni
,
165 uno_Interface
* pUnoI
, typelib_TypeDescription
* member_td
,
166 typelib_TypeDescriptionReference
* return_type
,
167 sal_Int32 nParams
, typelib_MethodParameter
const * pParams
,
168 jobjectArray jo_args
/* may be 0 */ ) const
171 sal_Int32 return_size
;
172 switch (return_type
->eTypeClass
) {
173 case typelib_TypeClass_VOID
:
177 case typelib_TypeClass_STRUCT
:
178 case typelib_TypeClass_EXCEPTION
:
179 return_size
= std::max(
180 TypeDescr(return_type
).get()->nSize
,
181 static_cast< sal_Int32
>(sizeof (largest
)));
185 return_size
= sizeof (largest
);
190 char * mem
= (char *) malloc(
192 char * mem
= (char *) alloca(
194 (nParams
* sizeof (void *)) +
195 return_size
+ (nParams
* sizeof (largest
)) );
196 void ** uno_args
= (void **) mem
;
197 void * uno_ret
= return_size
== 0 ? 0 : (mem
+ (nParams
* sizeof (void *)));
198 largest
* uno_args_mem
= (largest
*)
199 (mem
+ (nParams
* sizeof (void *)) + return_size
);
201 OSL_ASSERT( (0 == nParams
) || (nParams
== jni
->GetArrayLength( jo_args
)) );
202 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
204 typelib_MethodParameter
const & param
= pParams
[ nPos
];
205 typelib_TypeDescriptionReference
* type
= param
.pTypeRef
;
207 uno_args
[ nPos
] = &uno_args_mem
[ nPos
];
208 if (typelib_TypeClass_STRUCT
== type
->eTypeClass
||
209 typelib_TypeClass_EXCEPTION
== type
->eTypeClass
)
211 TypeDescr
td( type
);
212 if (sal::static_int_cast
< sal_uInt32
>(td
.get()->nSize
)
215 uno_args
[ nPos
] = malloc( td
.get()->nSize
);
217 uno_args
[ nPos
] = alloca( td
.get()->nSize
);
225 JLocalAutoRef
jo_arg(
226 jni
, jni
->GetObjectArrayElement( jo_args
, nPos
) );
227 jni
.ensure_no_exception();
229 java_arg
.l
= jo_arg
.get();
231 jni
, uno_args
[ nPos
], java_arg
, type
, 0,
232 false /* no assign */, sal_False
!= param
.bOut
,
233 true /* special wrapped integral types */ );
237 // cleanup uno in args
238 for ( sal_Int32 n
= 0; n
< nPos
; ++n
)
240 typelib_MethodParameter
const & p
= pParams
[ n
];
243 uno_type_destructData(
244 uno_args
[ n
], p
.pTypeRef
, 0 );
247 if (uno_args
[ nPos
] && uno_args
[ nPos
] != &uno_args_mem
[ nPos
])
248 free( uno_args
[ nPos
] );
259 uno_Any uno_exc_holder
;
260 uno_Any
* uno_exc
= &uno_exc_holder
;
262 (*pUnoI
->pDispatcher
)( pUnoI
, member_td
, uno_ret
, uno_args
, &uno_exc
);
266 // convert out args; destruct uno args
267 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
269 typelib_MethodParameter
const & param
= pParams
[ nPos
];
270 typelib_TypeDescriptionReference
* type
= param
.pTypeRef
;
275 // get out holder array[ 1 ]
276 JLocalAutoRef
jo_out_holder(
277 jni
, jni
->GetObjectArrayElement( jo_args
, nPos
) );
278 jni
.ensure_no_exception();
280 java_arg
.l
= jo_out_holder
.get();
282 jni
, &java_arg
, uno_args
[ nPos
], type
, 0,
283 true /* in */, true /* out holder */ );
287 // cleanup further uno args
288 for ( sal_Int32 n
= nPos
; n
< nParams
; ++n
)
290 uno_type_destructData(
291 uno_args
[ n
], pParams
[ n
].pTypeRef
, 0 );
293 if (uno_args
[ nPos
] && uno_args
[ nPos
] != &uno_args_mem
[ nPos
])
294 free( uno_args
[ nPos
] );
297 // cleanup uno return value
298 uno_type_destructData( uno_ret
, return_type
, 0 );
305 if (typelib_TypeClass_DOUBLE
< type
->eTypeClass
&&
306 typelib_TypeClass_ENUM
!= type
->eTypeClass
) // opt
308 uno_type_destructData( uno_args
[ nPos
], type
, 0 );
310 if (uno_args
[ nPos
] && uno_args
[ nPos
] != &uno_args_mem
[ nPos
])
311 free( uno_args
[ nPos
] );
316 if (typelib_TypeClass_VOID
!= return_type
->eTypeClass
)
318 // convert uno return value
323 jni
, &java_ret
, uno_ret
, return_type
, 0,
324 true /* in */, false /* no out */,
325 true /* special_wrapped_integral_types */ );
329 uno_type_destructData( uno_ret
, return_type
, 0 );
335 if (typelib_TypeClass_DOUBLE
< return_type
->eTypeClass
&&
336 typelib_TypeClass_ENUM
!= return_type
->eTypeClass
) // opt
338 uno_type_destructData( uno_ret
, return_type
, 0 );
348 return 0; // void return
350 else // exception occurred
352 // destruct uno in args
353 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
355 typelib_MethodParameter
const & param
= pParams
[ nPos
];
357 uno_type_destructData( uno_args
[ nPos
], param
.pTypeRef
, 0 );
359 if (uno_args
[ nPos
] && uno_args
[ nPos
] != &uno_args_mem
[ nPos
])
360 free( uno_args
[ nPos
] );
364 handle_uno_exc( jni
, uno_exc
);
374 using namespace ::jni_uno
;
379 //------------------------------------------------------------------------------
380 SAL_JNI_EXPORT jobject
381 JNICALL
Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
382 JNIEnv
* jni_env
, jobject jo_proxy
, jlong bridge_handle
, jstring jo_method
,
383 jobjectArray jo_args
/* may be 0 */ )
386 Bridge
const * bridge
= reinterpret_cast< Bridge
const * >( bridge_handle
);
387 JNI_info
const * jni_info
= bridge
->m_jni_info
;
390 static_cast< jobject
>(
391 reinterpret_cast< ::jvmaccess::UnoVirtualMachine
* >(
392 bridge
->m_java_env
->pContext
)->getClassLoader() ) );
394 OUString method_name
;
398 method_name
= jstring_to_oustring( jni
, jo_method
);
399 #if OSL_DEBUG_LEVEL > 1
401 OUStringBuffer
trace_buf( 64 );
402 trace_buf
.append( "java->uno call: " );
403 trace_buf
.append( method_name
);
404 trace_buf
.append( " on oid " );
405 JLocalAutoRef
jo_oid(
406 jni
, jni
->GetObjectField(
407 jo_proxy
, jni_info
->m_field_JNI_proxy_m_oid
) );
408 trace_buf
.append( jstring_to_oustring( jni
, (jstring
) jo_oid
.get() ) );
411 trace_buf
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
) );
412 OSL_TRACE( "%s", cstr_msg
.getStr() );
416 // special IQueryInterface.queryInterface()
417 if ( method_name
== "queryInterface" )
420 JLocalAutoRef
jo_oid(
421 jni
, jni
->GetObjectField(
422 jo_proxy
, jni_info
->m_field_JNI_proxy_m_oid
) );
424 JLocalAutoRef
jo_type(
425 jni
, jni
->GetObjectArrayElement( jo_args
, 0 ) );
426 jni
.ensure_no_exception();
428 JLocalAutoRef
jo_type_name(
429 jni
, jni
->GetObjectField(
430 jo_type
.get(), jni_info
->m_field_Type__typeName
) );
431 if (! jo_type_name
.is())
433 throw BridgeRuntimeError(
434 "incomplete type object: no type name!" +
435 jni
.get_stack_trace() );
438 jstring_to_oustring( jni
, (jstring
) jo_type_name
.get() ) );
439 JNI_type_info
const * info
=
440 jni_info
->get_type_info( jni
, type_name
);
441 if (typelib_TypeClass_INTERFACE
!= info
->m_td
.get()->eTypeClass
)
443 throw BridgeRuntimeError(
444 "queryInterface() call demands an INTERFACE type!" );
446 JNI_interface_type_info
const * iface_info
=
447 static_cast< JNI_interface_type_info
const * >( info
);
449 // getRegisteredInterface() already tested in JNI_proxy:
450 // perform queryInterface call on binary uno interface
451 uno_Interface
* pUnoI
= reinterpret_cast< uno_Interface
* >(
453 jo_proxy
, jni_info
->m_field_JNI_proxy_m_receiver_handle
) );
456 void * uno_args
[] = { &iface_info
->m_td
.get()->pWeakRef
};
457 uno_Any uno_exc_holder
;
458 uno_Any
* uno_exc
= &uno_exc_holder
;
460 (*pUnoI
->pDispatcher
)(
461 pUnoI
, jni_info
->m_XInterface_queryInterface_td
.get(),
462 &uno_ret
, uno_args
, &uno_exc
);
466 if (typelib_TypeClass_INTERFACE
== uno_ret
.pType
->eTypeClass
)
468 uno_Interface
* pUnoRet
=
469 (uno_Interface
*) uno_ret
.pReserved
;
475 bridge
->map_to_java( jni
, pUnoRet
, iface_info
);
479 uno_any_destruct( &uno_ret
, 0 );
484 uno_any_destruct( &uno_ret
, 0 );
489 bridge
->handle_uno_exc( jni
, uno_exc
);
494 typelib_InterfaceTypeDescription
* td
=
495 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
497 jo_proxy
, jni_info
->m_field_JNI_proxy_m_td_handle
) );
498 uno_Interface
* pUnoI
=
499 reinterpret_cast< uno_Interface
* >(
501 jo_proxy
, jni_info
->m_field_JNI_proxy_m_receiver_handle
) );
503 typelib_TypeDescriptionReference
** ppAllMembers
= td
->ppAllMembers
;
504 for ( sal_Int32 nPos
= td
->nAllMembers
; nPos
--; )
506 // try to avoid getting typedescription as long as possible,
507 // because of a Mutex.acquire() in
508 // typelib_typedescriptionreference_getDescription()
509 typelib_TypeDescriptionReference
* member_type
=
510 ppAllMembers
[ nPos
];
512 // check method_name against fully qualified type_name
513 // of member_type; type_name is of the form
514 // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
515 OUString
const & type_name
=
516 OUString::unacquired( &member_type
->pTypeName
);
517 sal_Int32 offset
= type_name
.indexOf( ':' ) + 2;
519 offset
>= 2 && offset
< type_name
.getLength()
520 && type_name
[offset
- 1] == ':' );
521 sal_Int32 remainder
= type_name
.getLength() - offset
;
522 if (typelib_TypeClass_INTERFACE_METHOD
== member_type
->eTypeClass
)
524 if ((method_name
.getLength() == remainder
525 || (method_name
.getLength() < remainder
526 && type_name
[offset
+ method_name
.getLength()] == ':'))
527 && type_name
.match(method_name
, offset
))
529 TypeDescr
member_td( member_type
);
530 typelib_InterfaceMethodTypeDescription
* method_td
=
532 typelib_InterfaceMethodTypeDescription
* >(
534 return bridge
->call_uno(
535 jni
, pUnoI
, member_td
.get(),
536 method_td
->pReturnTypeRef
,
537 method_td
->nParams
, method_td
->pParams
,
544 typelib_TypeClass_INTERFACE_ATTRIBUTE
==
545 member_type
->eTypeClass
);
547 if (method_name
.getLength() >= 3
548 && (method_name
.getLength() - 3 == remainder
549 || (method_name
.getLength() - 3 < remainder
551 offset
+ (method_name
.getLength() - 3)] == ':'))
552 && method_name
[1] == 'e' && method_name
[2] == 't'
553 && rtl_ustr_compare_WithLength(
554 type_name
.getStr() + offset
,
555 method_name
.getLength() - 3,
556 method_name
.getStr() + 3,
557 method_name
.getLength() - 3) == 0)
559 if ('g' == method_name
[ 0 ])
561 TypeDescr
member_td( member_type
);
562 typelib_InterfaceAttributeTypeDescription
* attr_td
=
564 typelib_InterfaceAttributeTypeDescription
* >(
566 return bridge
->call_uno(
567 jni
, pUnoI
, member_td
.get(),
568 attr_td
->pAttributeTypeRef
,
572 else if ('s' == method_name
[ 0 ])
574 TypeDescr
member_td( member_type
);
575 typelib_InterfaceAttributeTypeDescription
* attr_td
=
577 typelib_InterfaceAttributeTypeDescription
* >(
579 if (! attr_td
->bReadOnly
)
581 typelib_MethodParameter param
;
582 param
.pTypeRef
= attr_td
->pAttributeTypeRef
;
583 param
.bIn
= sal_True
;
584 param
.bOut
= sal_False
;
585 return bridge
->call_uno(
586 jni
, pUnoI
, member_td
.get(),
587 jni_info
->m_void_type
.getTypeLibType(),
595 // the thing that should not be... no method info found!
596 OUStringBuffer
buf( 64 );
597 buf
.append( "calling undeclared function on interface " );
598 buf
.append( OUString::unacquired(
599 &((typelib_TypeDescription
*)td
)->pTypeName
) );
601 buf
.append( method_name
);
602 buf
.append( jni
.get_stack_trace() );
603 throw BridgeRuntimeError( buf
.makeStringAndClear() );
605 catch (const BridgeRuntimeError
& err
)
607 OUStringBuffer
buf( 128 );
608 buf
.append( "[jni_uno bridge error] " "Java calling UNO method " );
609 buf
.append( method_name
);
611 buf
.append( err
.m_message
);
612 // notify RuntimeException
615 buf
.makeStringAndClear(), RTL_TEXTENCODING_JAVA_UTF8
) );
616 OSL_FAIL( cstr_msg
.getStr() );
617 if (jni
->ThrowNew(jni_info
->m_class_RuntimeException
, cstr_msg
.getStr())
624 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
627 OString( "[jni_uno bridge error] "
628 "attaching current thread to java failed!" ) +
630 jni
.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8
) );
631 OSL_FAIL( cstr_msg
.getStr() );
632 if (jni
->ThrowNew(jni_info
->m_class_RuntimeException
, cstr_msg
.getStr())
641 //------------------------------------------------------------------------------
643 JNICALL
Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
644 JNIEnv
* jni_env
, jobject jo_proxy
, jlong bridge_handle
)
647 Bridge
const * bridge
= reinterpret_cast< Bridge
const * >( bridge_handle
);
648 JNI_info
const * jni_info
= bridge
->m_jni_info
;
651 static_cast< jobject
>(
652 reinterpret_cast< ::jvmaccess::UnoVirtualMachine
* >(
653 bridge
->m_java_env
->pContext
)->getClassLoader() ) );
655 uno_Interface
* pUnoI
= reinterpret_cast< uno_Interface
* >(
657 jo_proxy
, jni_info
->m_field_JNI_proxy_m_receiver_handle
) );
658 typelib_TypeDescription
* td
=
659 reinterpret_cast< typelib_TypeDescription
* >(
661 jo_proxy
, jni_info
->m_field_JNI_proxy_m_td_handle
) );
663 #if OSL_DEBUG_LEVEL > 1
665 JLocalAutoRef
jo_oid(
666 jni
, jni
->GetObjectField(
667 jo_proxy
, jni_info
->m_field_JNI_proxy_m_oid
) );
668 OUString
oid( jstring_to_oustring( jni
, (jstring
) jo_oid
.get() ) );
671 "freeing java uno proxy: " + oid
,
672 RTL_TEXTENCODING_ASCII_US
) );
673 OSL_TRACE( "%s", cstr_msg
.getStr() );
676 // revoke from uno env; has already been revoked from java env
677 (*bridge
->m_uno_env
->revokeInterface
)( bridge
->m_uno_env
, pUnoI
);
679 (*pUnoI
->release
)( pUnoI
);
680 // release typedescription handle
681 typelib_typedescription_release( td
);
682 // release bridge handle
688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */