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.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 occured, 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 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 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 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