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