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