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_connectivity.hxx"
30 
31 
32 #ifndef _CONNECTIVITY_JAVA_LANG_OBJJECT_HXX_
33 #include "java/lang/Class.hxx"
34 #endif
35 #include "connectivity/CommonTools.hxx"
36 #include <com/sun/star/uno/Exception.hpp>
37 #include "java/tools.hxx"
38 #include "java/sql/SQLException.hxx"
39 #include <vos/process.hxx>
40 #include <vos/mutex.hxx>
41 #include <osl/thread.h>
42 #include <com/sun/star/uno/Sequence.hxx>
43 #include "java/LocalRef.hxx"
44 #include "resource/jdbc_log.hrc"
45 #include <rtl/logfile.hxx>
46 #include <comphelper/logging.hxx>
47 
48 #include <memory>
49 
50 using namespace connectivity;
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::beans;
53 using namespace ::com::sun::star::sdbc;
54 using namespace ::com::sun::star::container;
55 using namespace ::com::sun::star::lang;
56 
57 
58 // -----------------------------------------------------------------------------
59 ::rtl::Reference< jvmaccess::VirtualMachine > getJavaVM2(const ::rtl::Reference< jvmaccess::VirtualMachine >& _rVM = ::rtl::Reference< jvmaccess::VirtualMachine >(),
60 														sal_Bool _bSet = sal_False)
61 {
62 	static ::rtl::Reference< jvmaccess::VirtualMachine > s_VM;
63 	if ( _rVM.is() || _bSet )
64 		s_VM = _rVM;
65 	return s_VM;
66 }
67 // -----------------------------------------------------------------------------
68 ::rtl::Reference< jvmaccess::VirtualMachine > java_lang_Object::getVM(const Reference<XMultiServiceFactory >& _rxFactory)
69 {
70 	::rtl::Reference< jvmaccess::VirtualMachine > xVM = getJavaVM2();
71 	if ( !xVM.is() && _rxFactory.is() )
72 		xVM = getJavaVM2(::connectivity::getJavaVM(_rxFactory));
73 
74 	return xVM;
75 }
76 // -----------------------------------------------------------------------------
77 SDBThreadAttach::SDBThreadAttach()
78  : m_aGuard(java_lang_Object::getVM())
79  , pEnv(NULL)
80 {
81 	pEnv = m_aGuard.getEnvironment();
82     OSL_ENSURE(pEnv,"Environment is nULL!");
83 }
84 // -----------------------------------------------------------------------------
85 SDBThreadAttach::~SDBThreadAttach()
86 {
87 }
88 // -----------------------------------------------------------------------------
89 oslInterlockedCount& getJavaVMRefCount()
90 {
91 	static oslInterlockedCount s_nRefCount = 0;
92 	return s_nRefCount;
93 }
94 // -----------------------------------------------------------------------------
95 void SDBThreadAttach::addRef()
96 {
97     osl_incrementInterlockedCount(&getJavaVMRefCount());
98 }
99 // -----------------------------------------------------------------------------
100 void SDBThreadAttach::releaseRef()
101 {
102     osl_decrementInterlockedCount(&getJavaVMRefCount());
103 	if ( getJavaVMRefCount() == 0 )
104 	{
105 		getJavaVM2(::rtl::Reference< jvmaccess::VirtualMachine >(),sal_True);
106 	}
107 }
108 // -----------------------------------------------------------------------------
109 // statische Variablen der Klasse:
110 jclass java_lang_Object::theClass = 0;
111 
112 jclass java_lang_Object::getMyClass() const
113 {
114 	if( !theClass )
115         theClass = findMyClass("java/lang/Object");
116 	return theClass;
117 }
118 // der eigentliche Konstruktor
119 java_lang_Object::java_lang_Object(const Reference<XMultiServiceFactory >& _rxFactory)
120             : m_xFactory(_rxFactory),object( 0 )
121 {
122     SDBThreadAttach::addRef();
123 }
124 
125 // der protected-Konstruktor fuer abgeleitete Klassen
126 java_lang_Object::java_lang_Object( JNIEnv * pXEnv, jobject myObj )
127 	: object( NULL )
128 {
129     SDBThreadAttach::addRef();
130 	if( pXEnv && myObj )
131 		object = pXEnv->NewGlobalRef( myObj );
132 }
133 
134 java_lang_Object::~java_lang_Object()
135 {
136 	if( object )
137 	{
138 		SDBThreadAttach t;
139         clearObject(*t.pEnv);
140 	}
141     SDBThreadAttach::releaseRef();
142 }
143 void java_lang_Object::clearObject(JNIEnv& rEnv)
144 {
145 	if( object )
146 	{
147 		rEnv.DeleteGlobalRef( object );
148 		object = NULL;
149 	}
150 }
151 
152 void java_lang_Object::clearObject()
153 {
154 	if( object )
155 	{
156 		SDBThreadAttach t;
157         clearObject(*t.pEnv);
158 	}
159 }
160 // der protected-Konstruktor fuer abgeleitete Klassen
161 void java_lang_Object::saveRef( JNIEnv * pXEnv, jobject myObj )
162 {
163 	OSL_ENSURE( myObj, "object in c++ -> Java Wrapper" );
164 	if( myObj )
165 		object = pXEnv->NewGlobalRef( myObj );
166 }
167 
168 
169 ::rtl::OUString java_lang_Object::toString() const
170 {
171     static jmethodID mID(NULL);
172     return callStringMethod("toString",mID);
173 }
174 
175 // --------------------------------------------------------------------------------
176 namespace
177 {
178     bool    lcl_translateJNIExceptionToUNOException(
179         JNIEnv* _pEnvironment, const Reference< XInterface >& _rxContext, SQLException& _out_rException )
180     {
181         jthrowable jThrow = _pEnvironment ? _pEnvironment->ExceptionOccurred() : NULL;
182         if ( !jThrow )
183             return false;
184 
185         _pEnvironment->ExceptionClear();
186             // we have to clear the exception here because we want to handle it itself
187 
188         if ( _pEnvironment->IsInstanceOf( jThrow, java_sql_SQLException_BASE::st_getMyClass() ) )
189         {
190             ::std::auto_ptr< java_sql_SQLException_BASE > pException( new java_sql_SQLException_BASE( _pEnvironment, jThrow ) );
191             _out_rException = SQLException( pException->getMessage(), _rxContext,
192                 pException->getSQLState(), pException->getErrorCode(), Any() );
193             return true;
194         }
195         else if ( _pEnvironment->IsInstanceOf( jThrow, java_lang_Throwable::st_getMyClass() ) )
196         {
197             ::std::auto_ptr< java_lang_Throwable > pThrow( new java_lang_Throwable( _pEnvironment, jThrow ) );
198             ::rtl::OUString sMessage = pThrow->getMessage();
199             if ( !sMessage.getLength() )
200                 sMessage = pThrow->getLocalizedMessage();
201             if(  !sMessage.getLength() )
202                 sMessage = pThrow->toString();
203             _out_rException = SQLException( sMessage, _rxContext, ::rtl::OUString(), -1, Any() );
204             return true;
205         }
206         else
207             _pEnvironment->DeleteLocalRef( jThrow );
208         return false;
209     }
210 }
211 
212 // --------------------------------------------------------------------------------
213 void java_lang_Object::ThrowLoggedSQLException( const ::comphelper::ResourceBasedEventLogger& _rLogger, JNIEnv* _pEnvironment,
214     const Reference< XInterface >& _rxContext )
215 {
216     SQLException aException;
217     if ( lcl_translateJNIExceptionToUNOException( _pEnvironment, _rxContext, aException ) )
218     {
219         _rLogger.log( ::com::sun::star::logging::LogLevel::SEVERE, STR_LOG_THROWING_EXCEPTION, aException.Message, aException.SQLState, aException.ErrorCode );
220         throw aException;
221     }
222 }
223 
224 // --------------------------------------------------------------------------------
225 void java_lang_Object::ThrowSQLException( JNIEnv* _pEnvironment, const Reference< XInterface>& _rxContext )
226 {
227     SQLException aException;
228     if ( lcl_translateJNIExceptionToUNOException( _pEnvironment, _rxContext, aException ) )
229         throw aException;
230 }
231 // -----------------------------------------------------------------------------
232 void java_lang_Object::obtainMethodId(JNIEnv* _pEnv,const char* _pMethodName, const char* _pSignature,jmethodID& _inout_MethodID) const
233 {
234     if  ( !_inout_MethodID )
235     {
236         _inout_MethodID  = _pEnv->GetMethodID( getMyClass(), _pMethodName, _pSignature );
237         OSL_ENSURE( _inout_MethodID, _pSignature );
238         if  ( !_inout_MethodID )
239             throw SQLException();
240     } // if  ( !_inout_MethodID )
241 }
242 // -----------------------------------------------------------------------------
243 sal_Bool java_lang_Object::callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const
244 {
245 	jboolean out( sal_False );
246 
247     SDBThreadAttach t;
248     OSL_ENSURE( t.pEnv, "java_lang_Object::callBooleanMethod: no Java enviroment anymore!" );
249     obtainMethodId(t.pEnv, _pMethodName,"()Z", _inout_MethodID);
250     // call method
251 	out = t.pEnv->CallBooleanMethod( object, _inout_MethodID );
252 	ThrowSQLException( t.pEnv, NULL );
253 
254 	return out;
255 }
256 // -----------------------------------------------------------------------------
257 sal_Bool java_lang_Object::callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const
258 {
259 	jboolean out( sal_False );
260     SDBThreadAttach t;
261     OSL_ENSURE( t.pEnv, "java_lang_Object::callBooleanMethodWithIntArg: no Java enviroment anymore!" );
262 	obtainMethodId(t.pEnv, _pMethodName,"(I)Z", _inout_MethodID);
263     // call method
264 	out = t.pEnv->CallBooleanMethod( object, _inout_MethodID, _nArgument );
265 	ThrowSQLException( t.pEnv, NULL );
266 
267 	return out;
268 }
269 // -------------------------------------------------------------------------
270 jobject java_lang_Object::callResultSetMethod( JNIEnv& _rEnv,const char* _pMethodName, jmethodID& _inout_MethodID ) const
271 {
272     // call method
273     jobject out = callObjectMethod(&_rEnv,_pMethodName,"()Ljava/sql/ResultSet;", _inout_MethodID);
274     return out;
275 }
276 // -------------------------------------------------------------------------
277 sal_Int32 java_lang_Object::callIntMethod( const char* _pMethodName, jmethodID& _inout_MethodID,bool _bIgnoreException ) const
278 {
279     SDBThreadAttach t;
280     OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java enviroment anymore!" );
281     obtainMethodId(t.pEnv, _pMethodName,"()I", _inout_MethodID);
282 
283     // call method
284 	jint out( t.pEnv->CallIntMethod( object, _inout_MethodID ) );
285     if ( _bIgnoreException )
286         isExceptionOccured(t.pEnv,sal_True);
287     else
288 	    ThrowSQLException( t.pEnv, NULL );
289 
290 	return (sal_Int32)out;
291 }
292 // -------------------------------------------------------------------------
293 sal_Int32 java_lang_Object::callIntMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nArgument ) const
294 {
295     SDBThreadAttach t;
296     OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java enviroment anymore!" );
297     obtainMethodId(t.pEnv, _pMethodName,"(I)I", _inout_MethodID);
298     // call method
299 	jint out( t.pEnv->CallIntMethod( object, _inout_MethodID , _nArgument) );
300 	ThrowSQLException( t.pEnv, NULL );
301 
302 	return (sal_Int32)out;
303 }
304 // -------------------------------------------------------------------------
305 void java_lang_Object::callVoidMethod( const char* _pMethodName, jmethodID& _inout_MethodID) const
306 {
307     SDBThreadAttach t;
308     OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java enviroment anymore!" );
309     obtainMethodId(t.pEnv, _pMethodName,"()V", _inout_MethodID);
310 
311     // call method
312 	t.pEnv->CallVoidMethod( object, _inout_MethodID );
313 	ThrowSQLException( t.pEnv, NULL );
314 }
315 // -------------------------------------------------------------------------
316 void java_lang_Object::callVoidMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument,bool _bIgnoreException ) const
317 {
318     SDBThreadAttach t;
319     OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java enviroment anymore!" );
320     obtainMethodId(t.pEnv, _pMethodName,"(I)V", _inout_MethodID);
321 
322     // call method
323 	t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument );
324     if ( _bIgnoreException )
325         isExceptionOccured(t.pEnv,sal_True);
326     else
327 	    ThrowSQLException( t.pEnv, NULL );
328 }
329 // -------------------------------------------------------------------------
330 void java_lang_Object::callVoidMethodWithBoolArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument,bool _bIgnoreException ) const
331 {
332     SDBThreadAttach t;
333     OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java enviroment anymore!" );
334     obtainMethodId(t.pEnv, _pMethodName,"(Z)V", _inout_MethodID);
335     // call method
336 	t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument );
337     if ( _bIgnoreException )
338         isExceptionOccured(t.pEnv,sal_True);
339     else
340 	    ThrowSQLException( t.pEnv, NULL );
341 }
342 // -----------------------------------------------------------------------------
343 ::rtl::OUString java_lang_Object::callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const
344 {
345     SDBThreadAttach t;
346     OSL_ENSURE( t.pEnv, "java_lang_Object::callStringMethod: no Java enviroment anymore!" );
347 
348     // call method
349     jstring out = (jstring)callObjectMethod(t.pEnv,_pMethodName,"()Ljava/lang/String;", _inout_MethodID);
350 	return JavaString2String( t.pEnv, out );
351 }
352 // -----------------------------------------------------------------------------
353 jobject java_lang_Object::callObjectMethod( JNIEnv * _pEnv,const char* _pMethodName,const char* _pSignature, jmethodID& _inout_MethodID ) const
354 {
355     // obtain method ID
356     obtainMethodId(_pEnv, _pMethodName,_pSignature, _inout_MethodID);
357     // call method
358 	jobject out = _pEnv->CallObjectMethod( object, _inout_MethodID);
359 	ThrowSQLException( _pEnv, NULL );
360     return out;
361 }
362 
363 // -----------------------------------------------------------------------------
364 jobject java_lang_Object::callObjectMethodWithIntArg( JNIEnv * _pEnv,const char* _pMethodName,const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const
365 {
366     obtainMethodId(_pEnv, _pMethodName,_pSignature, _inout_MethodID);
367     // call method
368 	jobject out = _pEnv->CallObjectMethod( object, _inout_MethodID,_nArgument );
369 	ThrowSQLException( _pEnv, NULL );
370     return out;
371 }
372 // -----------------------------------------------------------------------------
373 ::rtl::OUString java_lang_Object::callStringMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const
374 {
375     SDBThreadAttach t;
376     OSL_ENSURE( t.pEnv, "java_lang_Object::callStringMethod: no Java enviroment anymore!" );
377 	jstring out = (jstring)callObjectMethodWithIntArg(t.pEnv,_pMethodName,"(I)Ljava/lang/String;",_inout_MethodID,_nArgument);
378 	return JavaString2String( t.pEnv, out );
379 }
380 // -------------------------------------------------------------------------
381 void java_lang_Object::callVoidMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const ::rtl::OUString& _nArgument ) const
382 {
383     SDBThreadAttach t;
384     OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java enviroment anymore!" );
385     obtainMethodId(t.pEnv, _pMethodName,"(Ljava/lang/String;)V", _inout_MethodID);
386 
387     jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,_nArgument));
388     // call method
389 	t.pEnv->CallVoidMethod( object, _inout_MethodID , str.get());
390 	ThrowSQLException( t.pEnv, NULL );
391 }
392 // -------------------------------------------------------------------------
393 sal_Int32 java_lang_Object::callIntMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const ::rtl::OUString& _nArgument ) const
394 {
395     SDBThreadAttach t;
396     OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethodWithStringArg: no Java enviroment anymore!" );
397     obtainMethodId(t.pEnv, _pMethodName,"(Ljava/lang/String;)I", _inout_MethodID);
398 
399     //TODO: Check if the code below is needed
400             //jdbc::LocalRef< jstring > str( t.env(), convertwchar_tToJavaString( t.pEnv, sql ) );
401             //{
402             //    jdbc::ContextClassLoaderScope ccl( t.env(),
403             //        m_pConnection ? m_pConnection->getDriverClassLoader() : jdbc::GlobalRef< jobject >(),
404             //        m_aLogger,
405             //        *this
406             //    );
407 
408     jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,_nArgument));
409     // call method
410 	jint out = t.pEnv->CallIntMethod( object, _inout_MethodID , str.get());
411 	ThrowSQLException( t.pEnv, NULL );
412     return (sal_Int32)out;
413 }
414 // -----------------------------------------------------------------------------
415 jclass java_lang_Object::findMyClass(const char* _pClassName)
416 {
417 	// die Klasse muss nur einmal geholt werden, daher statisch
418 	SDBThreadAttach t;
419 	jclass tempClass = t.pEnv->FindClass(_pClassName); OSL_ENSURE(tempClass,"Java : FindClass nicht erfolgreich!");
420     if(!tempClass)
421 	{
422 		t.pEnv->ExceptionDescribe();
423 		t.pEnv->ExceptionClear();
424 	}
425 	jclass globClass = (jclass)t.pEnv->NewGlobalRef( tempClass );
426 	t.pEnv->DeleteLocalRef( tempClass );
427 	return globClass;
428 }
429 
430