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 .
20 #include <sal/config.h>
25 #include <sal/alloca.h>
27 #include "jni_bridge.h"
28 #include "jniunoenvironmentdata.hxx"
34 jobject
Bridge::map_to_java(
35 JNI_context
const & jni
,
36 uno_Interface
* pUnoI
, JNI_interface_type_info
const * info
) const
39 rtl_uString
* pOid
= 0;
40 (*m_uno_env
->getObjectIdentifier
)( m_uno_env
, &pOid
, pUnoI
);
42 OUString
oid( pOid
, SAL_NO_ACQUIRE
);
44 // opt getRegisteredInterface()
45 JLocalAutoRef
jo_oid( jni
, ustring_to_jstring( jni
, oid
.pData
) );
47 args
[ 0 ].l
= jo_oid
.get();
48 args
[ 1 ].l
= info
->m_type
;
49 jobject jo_iface
= jni
->CallObjectMethodA(
50 getJniInfo()->m_object_java_env
,
51 getJniInfo()->m_method_IEnvironment_getRegisteredInterface
, args
);
52 jni
.ensure_no_exception();
54 if (0 == jo_iface
) // no registered iface
56 // register uno interface
57 (*m_uno_env
->registerInterface
)(
58 m_uno_env
, reinterpret_cast< void ** >( &pUnoI
),
59 oid
.pData
, reinterpret_cast<typelib_InterfaceTypeDescription
*>(info
->m_td
.get()) );
61 // create java and register java proxy
64 args2
[ 0 ].j
= reinterpret_cast< sal_Int64
>( this );
65 (*pUnoI
->acquire
)( pUnoI
);
66 args2
[ 1 ].l
= getJniInfo()->m_object_java_env
;
67 args2
[ 2 ].j
= reinterpret_cast< sal_Int64
>( pUnoI
);
68 typelib_typedescription_acquire( info
->m_td
.get() );
69 args2
[ 3 ].j
= reinterpret_cast< sal_Int64
>( info
->m_td
.get() );
70 args2
[ 4 ].l
= info
->m_type
;
71 args2
[ 5 ].l
= jo_oid
.get();
72 args2
[ 6 ].l
= info
->m_proxy_ctor
;
73 auto * envData
= static_cast<jni_uno::JniUnoEnvironmentData
*>(
74 m_java_env
->pContext
);
76 osl::MutexGuard
g(envData
->mutex
);
77 args2
[ 7 ].l
= envData
->asynchronousFinalizer
;
79 jo_iface
= jni
->CallStaticObjectMethodA(
80 getJniInfo()->m_class_JNI_proxy
,
81 getJniInfo()->m_method_JNI_proxy_create
, args2
);
82 jni
.ensure_no_exception();
85 assert( 0 != jo_iface
);
91 void Bridge::handle_uno_exc( JNI_context
const & jni
, uno_Any
* uno_exc
) const
93 if (typelib_TypeClass_EXCEPTION
== uno_exc
->pType
->eTypeClass
)
95 #if OSL_DEBUG_LEVEL > 0
96 // append java stack trace to Message member
97 static_cast< ::com::sun::star::uno::Exception
* >(
98 uno_exc
->pData
)->Message
+= jni
.get_stack_trace();
102 "exception occurred java->uno: ["
103 << OUString::unacquired(&uno_exc
->pType
->pTypeName
) << "] "
104 << static_cast<css::uno::Exception
const *>(
105 uno_exc
->pData
)->Message
);
111 jni
, &java_exc
, uno_exc
->pData
, uno_exc
->pType
, 0,
112 true /* in */, false /* no out */ );
116 uno_any_destruct( uno_exc
, 0 );
119 uno_any_destruct( uno_exc
, 0 );
121 JLocalAutoRef
jo_exc( jni
, java_exc
.l
);
122 jint res
= jni
->Throw( static_cast<jthrowable
>(jo_exc
.get()) );
126 JLocalAutoRef
jo_descr(
127 jni
, jni
->CallObjectMethodA(
128 jo_exc
.get(), getJniInfo()->m_method_Object_toString
, 0 ) );
129 jni
.ensure_no_exception();
130 throw BridgeRuntimeError(
131 "throwing java exception failed: "
132 + jstring_to_oustring( jni
, static_cast<jstring
>(jo_descr
.get()) )
133 + jni
.get_stack_trace() );
139 "thrown exception is no uno exception: " +
140 OUString::unacquired( &uno_exc
->pType
->pTypeName
) +
141 jni
.get_stack_trace() );
142 uno_any_destruct( uno_exc
, 0 );
143 throw BridgeRuntimeError( message
);
156 jobject
Bridge::call_uno(
157 JNI_context
const & jni
,
158 uno_Interface
* pUnoI
, typelib_TypeDescription
* member_td
,
159 typelib_TypeDescriptionReference
* return_type
,
160 sal_Int32 nParams
, typelib_MethodParameter
const * pParams
,
161 jobjectArray jo_args
/* may be 0 */ ) const
164 sal_Int32 return_size
;
165 switch (return_type
->eTypeClass
) {
166 case typelib_TypeClass_VOID
:
170 case typelib_TypeClass_STRUCT
:
171 case typelib_TypeClass_EXCEPTION
:
172 return_size
= std::max(
173 TypeDescr(return_type
).get()->nSize
,
174 static_cast< sal_Int32
>(sizeof (largest
)));
178 return_size
= sizeof (largest
);
183 char * mem
= static_cast<char *>(malloc(
185 char * mem
= static_cast<char *>(alloca(
187 (nParams
* sizeof (void *)) +
188 return_size
+ (nParams
* sizeof (largest
)) ));
189 void ** uno_args
= reinterpret_cast<void **>(mem
);
190 void * uno_ret
= return_size
== 0 ? 0 : (mem
+ (nParams
* sizeof (void *)));
191 largest
* uno_args_mem
= reinterpret_cast<largest
*>
192 (mem
+ (nParams
* sizeof (void *)) + return_size
);
194 assert( (0 == nParams
) || (nParams
== jni
->GetArrayLength( jo_args
)) );
195 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
197 typelib_MethodParameter
const & param
= pParams
[ nPos
];
198 typelib_TypeDescriptionReference
* type
= param
.pTypeRef
;
200 uno_args
[ nPos
] = &uno_args_mem
[ nPos
];
201 if (typelib_TypeClass_STRUCT
== type
->eTypeClass
||
202 typelib_TypeClass_EXCEPTION
== type
->eTypeClass
)
204 TypeDescr
td( type
);
205 if (sal::static_int_cast
< sal_uInt32
>(td
.get()->nSize
)
208 uno_args
[ nPos
] = malloc( td
.get()->nSize
);
210 uno_args
[ nPos
] = alloca( td
.get()->nSize
);
218 JLocalAutoRef
jo_arg(
219 jni
, jni
->GetObjectArrayElement( jo_args
, nPos
) );
220 jni
.ensure_no_exception();
222 java_arg
.l
= jo_arg
.get();
224 jni
, uno_args
[ nPos
], java_arg
, type
, 0,
225 false /* no assign */, sal_False
!= param
.bOut
,
226 true /* special wrapped integral types */ );
230 // cleanup uno in args
231 for ( sal_Int32 n
= 0; n
< nPos
; ++n
)
233 typelib_MethodParameter
const & p
= pParams
[ n
];
236 uno_type_destructData(
237 uno_args
[ n
], p
.pTypeRef
, 0 );
240 if (uno_args
[ nPos
] && uno_args
[ nPos
] != &uno_args_mem
[ nPos
])
241 free( uno_args
[ nPos
] );
252 uno_Any uno_exc_holder
;
253 uno_Any
* uno_exc
= &uno_exc_holder
;
255 (*pUnoI
->pDispatcher
)( pUnoI
, member_td
, uno_ret
, uno_args
, &uno_exc
);
259 // convert out args; destruct uno args
260 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
262 typelib_MethodParameter
const & param
= pParams
[ nPos
];
263 typelib_TypeDescriptionReference
* type
= param
.pTypeRef
;
268 // get out holder array[ 1 ]
269 JLocalAutoRef
jo_out_holder(
270 jni
, jni
->GetObjectArrayElement( jo_args
, nPos
) );
271 jni
.ensure_no_exception();
273 java_arg
.l
= jo_out_holder
.get();
275 jni
, &java_arg
, uno_args
[ nPos
], type
, 0,
276 true /* in */, true /* out holder */ );
280 // cleanup further uno args
281 for ( sal_Int32 n
= nPos
; n
< nParams
; ++n
)
283 uno_type_destructData(
284 uno_args
[ n
], pParams
[ n
].pTypeRef
, 0 );
286 if (uno_args
[ nPos
] && uno_args
[ nPos
] != &uno_args_mem
[ nPos
])
287 free( uno_args
[ nPos
] );
290 // cleanup uno return value
291 uno_type_destructData( uno_ret
, return_type
, 0 );
298 if (typelib_TypeClass_DOUBLE
< type
->eTypeClass
&&
299 typelib_TypeClass_ENUM
!= type
->eTypeClass
) // opt
301 uno_type_destructData( uno_args
[ nPos
], type
, 0 );
303 if (uno_args
[ nPos
] && uno_args
[ nPos
] != &uno_args_mem
[ nPos
])
304 free( uno_args
[ nPos
] );
309 if (typelib_TypeClass_VOID
!= return_type
->eTypeClass
)
311 // convert uno return value
316 jni
, &java_ret
, uno_ret
, return_type
, 0,
317 true /* in */, false /* no out */,
318 true /* special_wrapped_integral_types */ );
322 uno_type_destructData( uno_ret
, return_type
, 0 );
328 if (typelib_TypeClass_DOUBLE
< return_type
->eTypeClass
&&
329 typelib_TypeClass_ENUM
!= return_type
->eTypeClass
) // opt
331 uno_type_destructData( uno_ret
, return_type
, 0 );
341 return 0; // void return
343 else // exception occurred
345 // destruct uno in args
346 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
348 typelib_MethodParameter
const & param
= pParams
[ nPos
];
350 uno_type_destructData( uno_args
[ nPos
], param
.pTypeRef
, 0 );
352 if (uno_args
[ nPos
] && uno_args
[ nPos
] != &uno_args_mem
[ nPos
])
353 free( uno_args
[ nPos
] );
357 handle_uno_exc( jni
, uno_exc
);
367 using namespace ::jni_uno
;
373 SAL_JNI_EXPORT jobject
374 JNICALL
Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call(
375 JNIEnv
* jni_env
, jobject jo_proxy
, jlong bridge_handle
, jstring jo_method
,
376 jobjectArray jo_args
/* may be 0 */ )
378 Bridge
const * bridge
= reinterpret_cast< Bridge
const * >( bridge_handle
);
379 JNI_info
const * jni_info
= bridge
->getJniInfo();
382 static_cast< jobject
>(
383 static_cast<JniUnoEnvironmentData
*>(bridge
->m_java_env
->pContext
)
384 ->machine
->getClassLoader()));
386 OUString method_name
;
390 method_name
= jstring_to_oustring( jni
, jo_method
);
393 "java->uno call: " << method_name
<< " on oid "
394 << jstring_to_oustring(
396 static_cast<jstring
>(
400 jo_proxy
, jni_info
->m_field_JNI_proxy_m_oid
))
402 // special IQueryInterface.queryInterface()
403 if ( method_name
== "queryInterface" )
406 JLocalAutoRef
jo_oid(
407 jni
, jni
->GetObjectField(
408 jo_proxy
, jni_info
->m_field_JNI_proxy_m_oid
) );
410 JLocalAutoRef
jo_type(
411 jni
, jni
->GetObjectArrayElement( jo_args
, 0 ) );
412 jni
.ensure_no_exception();
414 JLocalAutoRef
jo_type_name(
415 jni
, jni
->GetObjectField(
416 jo_type
.get(), jni_info
->m_field_Type__typeName
) );
417 if (! jo_type_name
.is())
419 throw BridgeRuntimeError(
420 "incomplete type object: no type name!" +
421 jni
.get_stack_trace() );
424 jstring_to_oustring( jni
, static_cast<jstring
>(jo_type_name
.get()) ) );
425 JNI_type_info
const * info
=
426 jni_info
->get_type_info( jni
, type_name
);
427 if (typelib_TypeClass_INTERFACE
!= info
->m_td
.get()->eTypeClass
)
429 throw BridgeRuntimeError(
430 "queryInterface() call demands an INTERFACE type!" );
432 JNI_interface_type_info
const * iface_info
=
433 static_cast< JNI_interface_type_info
const * >( info
);
435 // getRegisteredInterface() already tested in JNI_proxy:
436 // perform queryInterface call on binary uno interface
437 uno_Interface
* pUnoI
= reinterpret_cast< uno_Interface
* >(
439 jo_proxy
, jni_info
->m_field_JNI_proxy_m_receiver_handle
) );
442 void * uno_args
[] = { &iface_info
->m_td
.get()->pWeakRef
};
443 uno_Any uno_exc_holder
;
444 uno_Any
* uno_exc
= &uno_exc_holder
;
446 (*pUnoI
->pDispatcher
)(
447 pUnoI
, jni_info
->m_XInterface_queryInterface_td
.get(),
448 &uno_ret
, uno_args
, &uno_exc
);
452 if (typelib_TypeClass_INTERFACE
== uno_ret
.pType
->eTypeClass
)
454 uno_Interface
* pUnoRet
=
455 static_cast<uno_Interface
*>(uno_ret
.pReserved
);
461 bridge
->map_to_java( jni
, pUnoRet
, iface_info
);
465 uno_any_destruct( &uno_ret
, 0 );
470 uno_any_destruct( &uno_ret
, 0 );
475 bridge
->handle_uno_exc( jni
, uno_exc
);
480 typelib_InterfaceTypeDescription
* td
=
481 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
483 jo_proxy
, jni_info
->m_field_JNI_proxy_m_td_handle
) );
484 uno_Interface
* pUnoI
=
485 reinterpret_cast< uno_Interface
* >(
487 jo_proxy
, jni_info
->m_field_JNI_proxy_m_receiver_handle
) );
489 typelib_TypeDescriptionReference
** ppAllMembers
= td
->ppAllMembers
;
490 for ( sal_Int32 nPos
= td
->nAllMembers
; nPos
--; )
492 // try to avoid getting typedescription as long as possible,
493 // because of a Mutex.acquire() in
494 // typelib_typedescriptionreference_getDescription()
495 typelib_TypeDescriptionReference
* member_type
=
496 ppAllMembers
[ nPos
];
498 // check method_name against fully qualified type_name
499 // of member_type; type_name is of the form
500 // <name> "::" <method_name> *(":@" <idx> "," <idx> ":" <name>)
501 OUString
const & type_name
=
502 OUString::unacquired( &member_type
->pTypeName
);
503 sal_Int32 offset
= type_name
.indexOf( ':' ) + 2;
505 assert(offset
< type_name
.getLength());
506 assert(type_name
[offset
- 1] == ':' );
507 sal_Int32 remainder
= type_name
.getLength() - offset
;
508 if (typelib_TypeClass_INTERFACE_METHOD
== member_type
->eTypeClass
)
510 if ((method_name
.getLength() == remainder
511 || (method_name
.getLength() < remainder
512 && type_name
[offset
+ method_name
.getLength()] == ':'))
513 && type_name
.match(method_name
, offset
))
515 TypeDescr
member_td( member_type
);
516 typelib_InterfaceMethodTypeDescription
* method_td
=
518 typelib_InterfaceMethodTypeDescription
* >(
520 return bridge
->call_uno(
521 jni
, pUnoI
, member_td
.get(),
522 method_td
->pReturnTypeRef
,
523 method_td
->nParams
, method_td
->pParams
,
530 typelib_TypeClass_INTERFACE_ATTRIBUTE
==
531 member_type
->eTypeClass
);
533 if (method_name
.getLength() >= 3
534 && (method_name
.getLength() - 3 == remainder
535 || (method_name
.getLength() - 3 < remainder
537 offset
+ (method_name
.getLength() - 3)] == ':'))
538 && method_name
[1] == 'e' && method_name
[2] == 't'
539 && rtl_ustr_compare_WithLength(
540 type_name
.getStr() + offset
,
541 method_name
.getLength() - 3,
542 method_name
.getStr() + 3,
543 method_name
.getLength() - 3) == 0)
545 if ('g' == method_name
[ 0 ])
547 TypeDescr
member_td( member_type
);
548 typelib_InterfaceAttributeTypeDescription
* attr_td
=
550 typelib_InterfaceAttributeTypeDescription
* >(
552 return bridge
->call_uno(
553 jni
, pUnoI
, member_td
.get(),
554 attr_td
->pAttributeTypeRef
,
558 else if ('s' == method_name
[ 0 ])
560 TypeDescr
member_td( member_type
);
561 typelib_InterfaceAttributeTypeDescription
* attr_td
=
563 typelib_InterfaceAttributeTypeDescription
* >(
565 if (! attr_td
->bReadOnly
)
567 typelib_MethodParameter param
;
568 param
.pTypeRef
= attr_td
->pAttributeTypeRef
;
569 param
.bIn
= sal_True
;
570 param
.bOut
= sal_False
;
571 return bridge
->call_uno(
572 jni
, pUnoI
, member_td
.get(),
573 jni_info
->m_void_type
.getTypeLibType(),
581 // the thing that should not be... no method info found!
582 throw BridgeRuntimeError(
583 "calling undeclared function on interface "
584 + OUString::unacquired(&td
->aBase
.pTypeName
)
585 + ": " + method_name
+ jni
.get_stack_trace() );
587 catch (const BridgeRuntimeError
& err
)
591 "Java calling UNO method " << method_name
<< ": " << err
.m_message
);
592 // notify RuntimeException
594 "[jni_uno bridge error] Java calling UNO method "
595 + OUStringToOString(method_name
, RTL_TEXTENCODING_JAVA_UTF8
) + ": "
596 + OUStringToOString(err
.m_message
, RTL_TEXTENCODING_JAVA_UTF8
));
597 if (jni
->ThrowNew(jni_info
->m_class_RuntimeException
, cstr_msg
.getStr())
604 catch (const ::jvmaccess::VirtualMachine::AttachGuard::CreationException
&)
606 SAL_WARN("bridges", "attaching current thread to java failed");
608 "[jni_uno bridge error] attaching current thread to java failed"
610 jni
.get_stack_trace(), RTL_TEXTENCODING_JAVA_UTF8
));
611 if (jni
->ThrowNew(jni_info
->m_class_RuntimeException
, cstr_msg
.getStr())
622 JNICALL
Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_finalize__J(
623 JNIEnv
* jni_env
, jobject jo_proxy
, jlong bridge_handle
)
625 Bridge
const * bridge
= reinterpret_cast< Bridge
const * >( bridge_handle
);
626 JNI_info
const * jni_info
= bridge
->getJniInfo();
629 static_cast< jobject
>(
630 static_cast<JniUnoEnvironmentData
*>(bridge
->m_java_env
->pContext
)
631 ->machine
->getClassLoader()));
633 uno_Interface
* pUnoI
= reinterpret_cast< uno_Interface
* >(
635 jo_proxy
, jni_info
->m_field_JNI_proxy_m_receiver_handle
) );
636 typelib_TypeDescription
* td
=
637 reinterpret_cast< typelib_TypeDescription
* >(
639 jo_proxy
, jni_info
->m_field_JNI_proxy_m_td_handle
) );
642 "freeing java uno proxy: "
643 << jstring_to_oustring(
645 static_cast<jstring
>(
649 jo_proxy
, jni_info
->m_field_JNI_proxy_m_oid
))
651 // revoke from uno env; has already been revoked from java env
652 (*bridge
->m_uno_env
->revokeInterface
)( bridge
->m_uno_env
, pUnoI
);
654 (*pUnoI
->release
)( pUnoI
);
655 // release typedescription handle
656 typelib_typedescription_release( td
);
657 // release bridge handle
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */