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