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