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