bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / jdbc / JConnection.cxx
blob0529979e2b5b4e245a7905a5a07b5516fccd3317
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <java/sql/Connection.hxx>
23 #include <java/lang/Class.hxx>
24 #include <java/tools.hxx>
25 #include <java/ContextClassLoader.hxx>
26 #include <java/sql/DatabaseMetaData.hxx>
27 #include <java/sql/JStatement.hxx>
28 #include <java/sql/Driver.hxx>
29 #include <java/sql/PreparedStatement.hxx>
30 #include <java/sql/CallableStatement.hxx>
31 #include <java/sql/SQLWarning.hxx>
32 #include <com/sun/star/sdbc/SQLWarning.hpp>
33 #include <com/sun/star/beans/NamedValue.hpp>
34 #include <connectivity/dbexception.hxx>
35 #include <java/util/Property.hxx>
36 #include <java/LocalRef.hxx>
37 #include <com/sun/star/uno/XComponentContext.hpp>
38 #include <jvmaccess/classpath.hxx>
39 #include <comphelper/namedvaluecollection.hxx>
40 #include <cppuhelper/exc_hlp.hxx>
41 #include <jni.h>
42 #include <strings.hrc>
43 #include <unotools/confignode.hxx>
44 #include <strings.hxx>
46 #include <vector>
47 #include <memory>
49 using namespace connectivity;
50 using namespace connectivity::jdbc;
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;
57 namespace {
59 struct ClassMapEntry {
60 ClassMapEntry(
61 OUString const & theClassPath, OUString const & theClassName):
62 classPath(theClassPath), className(theClassName), classLoader(nullptr),
63 classObject(nullptr) {}
65 OUString classPath;
66 OUString className;
67 jweak classLoader;
68 jweak classObject;
71 typedef std::vector< ClassMapEntry > ClassMap;
73 struct ClassMapData {
74 osl::Mutex mutex;
76 ClassMap map;
79 template < typename T >
80 bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local )
82 _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) );
84 if ( !_inout_local.is() )
86 if ( _inout_local.env().ExceptionCheck())
88 return false;
90 else if ( _weak != nullptr )
92 _inout_local.env().DeleteWeakGlobalRef( _weak );
93 _weak = nullptr;
96 return true;
99 // Load a class. A map from pairs of (classPath, name) to pairs of weak Java
100 // references to (ClassLoader, Class) is maintained, so that a class is only
101 // loaded once.
103 // It may happen that the weak reference to the ClassLoader becomes null while
104 // the reference to the Class remains non-null (in case the Class was actually
105 // loaded by some parent of the ClassLoader), in which case the ClassLoader is
106 // resurrected (which cannot cause any classes to be loaded multiple times, as
107 // the ClassLoader is no longer reachable, so no classes it has ever loaded are
108 // still reachable).
110 // Similarly, it may happen that the weak reference to the Class becomes null
111 // while the reference to the ClassLoader remains non-null, in which case the
112 // Class is simply re-loaded.
114 // This code is close to the implementation of jvmaccess::ClassPath::loadClass
115 // in jvmaccess/classpath.hxx, but not close enough to avoid the duplication.
117 // If false is returned, a (still pending) JNI exception occurred.
118 bool loadClass(
119 Reference< XComponentContext > const & context, JNIEnv& environment,
120 OUString const & classPath, OUString const & name,
121 LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr)
123 OSL_ASSERT(classLoaderPtr != nullptr);
124 // For any jweak entries still present in the map upon destruction,
125 // DeleteWeakGlobalRef is not called (which is a leak):
126 static ClassMapData classMapData;
127 osl::MutexGuard g(classMapData.mutex);
128 ClassMap::iterator i(classMapData.map.begin());
129 LocalRef< jobject > cloader(environment);
130 LocalRef< jclass > cl(environment);
131 // Prune dangling weak references from the list while searching for a match,
132 // so that the list cannot grow unbounded:
133 for (; i != classMapData.map.end();)
135 LocalRef< jobject > classLoader( environment );
136 if ( !getLocalFromWeakRef( i->classLoader, classLoader ) )
137 return false;
139 LocalRef< jclass > classObject( environment );
140 if ( !getLocalFromWeakRef( i->classObject, classObject ) )
141 return false;
143 if ( !classLoader.is() && !classObject.is() )
145 i = classMapData.map.erase(i);
147 else if ( i->classPath == classPath && i->className == name )
149 cloader.set( classLoader.release() );
150 cl.set( classObject.release() );
151 break;
153 else
155 ++i;
158 if ( !cloader.is() || !cl.is() )
160 if ( i == classMapData.map.end() )
162 // Push a new ClassMapEntry (which can potentially fail) before
163 // loading the class, so that it never happens that a class is
164 // loaded but not added to the map (which could have effects on the
165 // JVM that are not easily undone). If the pushed ClassMapEntry is
166 // not used after all (return false, etc.) it will be pruned on next
167 // call because its classLoader/classObject are null:
168 classMapData.map.push_back( ClassMapEntry( classPath, name ) );
169 i = std::prev(classMapData.map.end());
172 LocalRef< jclass > clClass( environment );
173 clClass.set( environment.FindClass( "java/net/URLClassLoader" ) );
174 if ( !clClass.is() )
175 return false;
177 jweak wcloader = nullptr;
178 if (!cloader.is())
180 jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) );
181 if (ctorLoader == nullptr)
182 return false;
184 LocalRef< jobjectArray > arr( environment );
185 arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) );
186 if ( !arr.is() )
187 return false;
189 jvalue arg;
190 arg.l = arr.get();
191 cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) );
192 if ( !cloader.is() )
193 return false;
195 wcloader = environment.NewWeakGlobalRef( cloader.get() );
196 if ( wcloader == nullptr )
197 return false;
200 jweak wcl = nullptr;
201 if ( !cl.is() )
203 jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) );
204 if ( methLoadClass == nullptr )
205 return false;
207 LocalRef< jstring > str( environment );
208 str.set( convertwchar_tToJavaString( &environment, name ) );
209 if ( !str.is() )
210 return false;
212 jvalue arg;
213 arg.l = str.get();
214 cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) );
215 if ( !cl.is() )
216 return false;
218 wcl = environment.NewWeakGlobalRef( cl.get() );
219 if ( wcl == nullptr )
220 return false;
223 if ( wcloader != nullptr)
225 i->classLoader = wcloader;
227 if ( wcl != nullptr )
229 i->classObject = wcl;
233 classLoaderPtr->set( cloader.release() );
234 classPtr->set( cl.release() );
235 return true;
241 IMPLEMENT_SERVICE_INFO(java_sql_Connection,"com.sun.star.sdbcx.JConnection","com.sun.star.sdbc.Connection");
244 //************ Class: java.sql.Connection
246 jclass java_sql_Connection::theClass = nullptr;
248 java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver )
249 :java_lang_Object()
250 ,m_xContext( _rDriver.getContext() )
251 ,m_pDriver( &_rDriver )
252 ,m_pDriverobject(nullptr)
253 ,m_pDriverClassLoader()
254 ,m_Driver_theClass(nullptr)
255 ,m_aLogger( _rDriver.getLogger() )
256 ,m_bIgnoreDriverPrivileges(true)
257 ,m_bIgnoreCurrency(false)
261 java_sql_Connection::~java_sql_Connection()
263 ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM();
264 if ( !xTest.is() )
265 return;
267 SDBThreadAttach t;
268 clearObject(*t.pEnv);
271 if ( m_pDriverobject )
272 t.pEnv->DeleteGlobalRef( m_pDriverobject );
273 m_pDriverobject = nullptr;
274 if ( m_Driver_theClass )
275 t.pEnv->DeleteGlobalRef( m_Driver_theClass );
276 m_Driver_theClass = nullptr;
278 SDBThreadAttach::releaseRef();
281 void java_sql_Connection::disposing()
283 ::osl::MutexGuard aGuard(m_aMutex);
285 m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION );
287 java_sql_Connection_BASE::disposing();
289 if ( object )
291 static jmethodID mID(nullptr);
292 callVoidMethod_ThrowSQL("close", mID);
296 jclass java_sql_Connection::getMyClass() const
298 // the class must be fetched only once, therefore static
299 if( !theClass )
300 theClass = findMyClass("java/sql/Connection");
301 return theClass;
305 OUString SAL_CALL java_sql_Connection::getCatalog( )
307 ::osl::MutexGuard aGuard( m_aMutex );
308 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
310 static jmethodID mID(nullptr);
311 return callStringMethod("getCatalog",mID);
314 Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( )
316 ::osl::MutexGuard aGuard( m_aMutex );
317 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
320 Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
321 if(!xMetaData.is())
323 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
324 static jmethodID mID(nullptr);
325 jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID);
326 if(out)
328 xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this );
329 m_xMetaData = xMetaData;
333 return xMetaData;
336 void SAL_CALL java_sql_Connection::close( )
338 dispose();
341 void SAL_CALL java_sql_Connection::commit( )
343 static jmethodID mID(nullptr);
344 callVoidMethod_ThrowSQL("commit", mID);
347 sal_Bool SAL_CALL java_sql_Connection::isClosed( )
349 ::osl::MutexGuard aGuard( m_aMutex );
351 static jmethodID mID(nullptr);
352 return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed;
355 sal_Bool SAL_CALL java_sql_Connection::isReadOnly( )
357 ::osl::MutexGuard aGuard( m_aMutex );
358 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
359 static jmethodID mID(nullptr);
360 return callBooleanMethod( "isReadOnly", mID );
363 void SAL_CALL java_sql_Connection::setCatalog( const OUString& catalog )
365 static jmethodID mID(nullptr);
366 callVoidMethodWithStringArg("setCatalog",mID,catalog);
369 void SAL_CALL java_sql_Connection::rollback( )
371 static jmethodID mID(nullptr);
372 callVoidMethod_ThrowSQL("rollback", mID);
375 sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( )
377 static jmethodID mID(nullptr);
378 return callBooleanMethod( "getAutoCommit", mID );
381 void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly )
383 static jmethodID mID(nullptr);
384 callVoidMethodWithBoolArg_ThrowSQL("setReadOnly", mID, readOnly);
387 void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit )
389 static jmethodID mID(nullptr);
390 callVoidMethodWithBoolArg_ThrowSQL("setAutoCommit", mID, autoCommit);
393 Reference< css::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( )
395 ::osl::MutexGuard aGuard( m_aMutex );
396 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
398 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
399 static jmethodID mID(nullptr);
400 callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID);
401 // WARNING: the caller becomes the owner of the returned pointer
402 return nullptr;
405 void SAL_CALL java_sql_Connection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ )
407 ::osl::MutexGuard aGuard( m_aMutex );
408 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
410 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
414 sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( )
416 ::osl::MutexGuard aGuard( m_aMutex );
417 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
419 static jmethodID mID(nullptr);
420 return callIntMethod_ThrowSQL("getTransactionIsolation", mID);
423 void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level )
425 ::osl::MutexGuard aGuard( m_aMutex );
426 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
428 static jmethodID mID(nullptr);
429 callVoidMethodWithIntArg_ThrowSQL("setTransactionIsolation", mID, level);
432 Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( )
434 ::osl::MutexGuard aGuard( m_aMutex );
435 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
436 m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT );
438 SDBThreadAttach t;
439 rtl::Reference<java_sql_Statement> pStatement = new java_sql_Statement( t.pEnv, *this );
440 Reference< XStatement > xStmt = pStatement;
441 m_aStatements.push_back( WeakReferenceHelper( xStmt ) );
443 m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() );
444 return xStmt;
447 Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql )
449 ::osl::MutexGuard aGuard( m_aMutex );
450 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
451 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
453 SDBThreadAttach t;
455 rtl::Reference<java_sql_PreparedStatement> pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sql );
456 Reference< XPreparedStatement > xReturn( pStatement );
457 m_aStatements.push_back(WeakReferenceHelper(xReturn));
459 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() );
460 return xReturn;
463 Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const OUString& sql )
465 ::osl::MutexGuard aGuard( m_aMutex );
466 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
467 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql );
469 SDBThreadAttach t;
471 rtl::Reference<java_sql_CallableStatement> pStatement = new java_sql_CallableStatement( t.pEnv, *this, sql );
472 Reference< XPreparedStatement > xStmt( pStatement );
473 m_aStatements.push_back(WeakReferenceHelper(xStmt));
475 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() );
476 return xStmt;
479 OUString SAL_CALL java_sql_Connection::nativeSQL( const OUString& sql )
481 ::osl::MutexGuard aGuard( m_aMutex );
482 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
484 OUString aStr;
485 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
488 // initialize temporary Variable
489 static const char * const cSignature = "(Ljava/lang/String;)Ljava/lang/String;";
490 static const char * const cMethodName = "nativeSQL";
491 // Java-Call
492 static jmethodID mID(nullptr);
493 obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
494 // Convert Parameter
495 jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql));
497 jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() );
498 aStr = JavaString2String(t.pEnv, static_cast<jstring>(out) );
499 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
500 } //t.pEnv
502 m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr );
504 return aStr;
507 void SAL_CALL java_sql_Connection::clearWarnings( )
509 static jmethodID mID(nullptr);
510 callVoidMethod_ThrowSQL("clearWarnings", mID);
513 Any SAL_CALL java_sql_Connection::getWarnings( )
515 ::osl::MutexGuard aGuard( m_aMutex );
516 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
518 SDBThreadAttach t;
519 static jmethodID mID(nullptr);
520 jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
521 // WARNING: the caller becomes the owner of the returned pointer
522 if( out )
524 java_sql_SQLWarning_BASE warn_base(t.pEnv, out);
525 SQLException aAsException( java_sql_SQLWarning( warn_base, *this ) );
527 // translate to warning
528 SQLWarning aWarning;
529 aWarning.Context = aAsException.Context;
530 aWarning.Message = aAsException.Message;
531 aWarning.SQLState = aAsException.SQLState;
532 aWarning.ErrorCode = aAsException.ErrorCode;
533 aWarning.NextException = aAsException.NextException;
535 return makeAny( aWarning );
538 return Any();
542 namespace
544 OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const OUString& _rDriverClass, const OUString& _rDriverClassPath )
546 OUString sError1( _aResource.getResourceStringWithSubstitution(
547 STR_NO_CLASSNAME,
548 "$classname$", _rDriverClass
549 ) );
550 if ( !_rDriverClassPath.isEmpty() )
552 const OUString sError2( _aResource.getResourceStringWithSubstitution(
553 STR_NO_CLASSNAME_PATH,
554 "$classpath$", _rDriverClassPath
555 ) );
556 sError1 += sError2;
557 } // if ( _rDriverClassPath.getLength() )
558 return sError1;
563 namespace
565 bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger,
566 JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties )
568 if ( !_rSystemProperties.hasElements() )
569 // nothing to do
570 return true;
572 LocalRef< jclass > systemClass( _rEnv );
573 jmethodID nSetPropertyMethodID = nullptr;
574 // retrieve the java.lang.System class
575 systemClass.set( _rEnv.FindClass( "java/lang/System" ) );
576 if ( systemClass.is() )
578 nSetPropertyMethodID = _rEnv.GetStaticMethodID(
579 systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
582 if ( nSetPropertyMethodID == nullptr )
583 return false;
585 for ( auto const & systemProp : _rSystemProperties )
587 OUString sValue;
588 OSL_VERIFY( systemProp.Value >>= sValue );
590 _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, systemProp.Name, sValue );
592 LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, systemProp.Name ) );
593 LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) );
595 _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() );
596 LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() );
597 if ( throwable.is() )
598 return false;
601 return true;
606 void java_sql_Connection::loadDriverFromProperties( const OUString& _sDriverClass, const OUString& _sDriverClassPath,
607 const Sequence< NamedValue >& _rSystemProperties )
609 // first try if the jdbc driver is already registered at the driver manager
610 SDBThreadAttach t;
613 if ( !object )
615 if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) )
616 ThrowLoggedSQLException( getLogger(), t.pEnv, *this );
618 m_pDriverClassLoader.reset();
620 // here I try to find the class for jdbc driver
621 java_sql_SQLException_BASE::st_getMyClass();
622 java_lang_Throwable::st_getMyClass();
624 if ( _sDriverClass.isEmpty() )
626 m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS );
627 ::dbtools::throwGenericSQLException(
628 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
629 *this
632 else
634 m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass );
635 // the driver manager holds the class of the driver for later use
636 std::unique_ptr< java_lang_Class > pDrvClass;
637 if ( _sDriverClassPath.isEmpty() )
639 // if forName didn't find the class it will throw an exception
640 pDrvClass.reset(java_lang_Class::forName(_sDriverClass));
642 else
644 LocalRef< jclass > driverClass(t.env());
645 LocalRef< jobject > driverClassLoader(t.env());
647 loadClass(
648 m_pDriver->getContext(),
649 t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass );
651 m_pDriverClassLoader.set( driverClassLoader );
652 pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) );
654 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
656 if (pDrvClass)
658 LocalRef< jobject > driverObject( t.env() );
659 driverObject.set( pDrvClass->newInstanceObject() );
660 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
661 m_pDriverobject = driverObject.release();
663 if( m_pDriverobject )
664 m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject );
667 jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject);
668 if ( m_pDriverobject )
670 m_Driver_theClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass ));
671 t.pEnv->DeleteLocalRef( tempClass );
675 m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS );
679 catch( const SQLException& )
681 css::uno::Any anyEx = cppu::getCaughtException();
682 throw SQLException(
683 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
684 *this,
685 OUString(),
686 1000,
687 anyEx);
689 catch( Exception& )
691 css::uno::Any anyEx = cppu::getCaughtException();
692 ::dbtools::throwGenericSQLException(
693 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
694 *this,
695 anyEx
700 OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass)
702 static constexpr OUStringLiteral s_sNodeName
703 = u"org.openoffice.Office.DataAccess/JDBC/DriverClassPaths";
704 ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext(
705 m_pDriver->getContext(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
706 OUString sURL;
707 if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) )
709 ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass );
710 OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL );
712 return sURL;
715 bool java_sql_Connection::construct(const OUString& url,
716 const Sequence< PropertyValue >& info)
718 { // initialize the java vm
719 ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(m_xContext);
720 if ( !xTest.is() )
721 throwGenericSQLException(STR_NO_JAVA,*this);
723 SDBThreadAttach t;
724 SDBThreadAttach::addRef(); // will be released in dtor
725 if ( !t.pEnv )
726 throwGenericSQLException(STR_NO_JAVA,*this);
728 OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
729 bool bAutoRetrievingEnabled = false; // set to <TRUE/> when we should allow to query for generated values
730 OUString sDriverClassPath,sDriverClass;
731 Sequence< NamedValue > aSystemProperties;
733 ::comphelper::NamedValueCollection aSettings( info );
734 sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass );
735 sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath);
736 if ( sDriverClassPath.isEmpty() )
737 sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
738 bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
739 sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
740 m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
741 m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
742 aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
743 m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() );
744 m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() );
746 loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties );
748 enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
749 setAutoRetrievingStatement(sGeneratedValueStatement);
751 if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
753 // Java-Call
754 static const char * const cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;";
755 static const char * const cMethodName = "connect";
756 jmethodID mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature );
758 if ( mID )
760 jvalue args[2];
761 // convert Parameter
762 args[0].l = convertwchar_tToJavaString(t.pEnv,url);
763 std::unique_ptr<java_util_Properties> pProps = createStringPropertyArray(info);
764 args[1].l = pProps->getJavaObject();
766 LocalRef< jobject > ensureDelete( t.env(), args[0].l );
768 jobject out = nullptr;
769 // In some cases (e.g.,
770 // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
771 // l. 249) the JavaDriverClassPath contains multiple jars,
772 // as creating the JavaDriverClass instance requires
773 // (reflective) access to those other jars. Now, if the
774 // JavaDriverClass is actually loaded by some parent class
775 // loader (e.g., because its jar is also on the global
776 // class path), it would still not have access to the
777 // additional jars on the JavaDriverClassPath. Hence, the
778 // JavaDriverClassPath class loader is pushed as context
779 // class loader around the JavaDriverClass instance
780 // creation:
781 // #i82222# / 2007-10-15
783 ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this );
784 out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l );
785 pProps.reset();
786 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
789 if ( !out )
790 m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION );
792 if ( out )
793 object = t.pEnv->NewGlobalRef( out );
795 if ( object )
796 m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url );
798 m_aConnectionInfo = info;
799 } //mID
800 } //t.pEnv
801 return object != nullptr;
805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */