summaryrefslogtreecommitdiffstats
path: root/connectivity/source/drivers/jdbc/JConnection.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /connectivity/source/drivers/jdbc/JConnection.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream/4%7.4.7.tar.xz
libreoffice-upstream/4%7.4.7.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'connectivity/source/drivers/jdbc/JConnection.cxx')
-rw-r--r--connectivity/source/drivers/jdbc/JConnection.cxx803
1 files changed, 803 insertions, 0 deletions
diff --git a/connectivity/source/drivers/jdbc/JConnection.cxx b/connectivity/source/drivers/jdbc/JConnection.cxx
new file mode 100644
index 000000000..19391e60e
--- /dev/null
+++ b/connectivity/source/drivers/jdbc/JConnection.cxx
@@ -0,0 +1,803 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <java/sql/Connection.hxx>
+#include <java/lang/Class.hxx>
+#include <java/tools.hxx>
+#include <java/ContextClassLoader.hxx>
+#include <java/sql/DatabaseMetaData.hxx>
+#include <java/sql/JStatement.hxx>
+#include <java/sql/Driver.hxx>
+#include <java/sql/PreparedStatement.hxx>
+#include <java/sql/CallableStatement.hxx>
+#include <java/sql/SQLWarning.hxx>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <connectivity/dbexception.hxx>
+#include <java/util/Property.hxx>
+#include <java/LocalRef.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <jvmaccess/classpath.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <jni.h>
+#include <strings.hrc>
+#include <unotools/confignode.hxx>
+#include <strings.hxx>
+
+#include <vector>
+#include <memory>
+
+using namespace connectivity;
+using namespace connectivity::jdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace {
+
+struct ClassMapEntry {
+ ClassMapEntry(
+ OUString const & theClassPath, OUString const & theClassName):
+ classPath(theClassPath), className(theClassName), classLoader(nullptr),
+ classObject(nullptr) {}
+
+ OUString classPath;
+ OUString className;
+ jweak classLoader;
+ jweak classObject;
+};
+
+typedef std::vector< ClassMapEntry > ClassMap;
+
+struct ClassMapData {
+ osl::Mutex mutex;
+
+ ClassMap map;
+};
+
+template < typename T >
+bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local )
+{
+ _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) );
+
+ if ( !_inout_local.is() )
+ {
+ if ( _inout_local.env().ExceptionCheck())
+ {
+ return false;
+ }
+ else if ( _weak != nullptr )
+ {
+ _inout_local.env().DeleteWeakGlobalRef( _weak );
+ _weak = nullptr;
+ }
+ }
+ return true;
+}
+
+// Load a class. A map from pairs of (classPath, name) to pairs of weak Java
+// references to (ClassLoader, Class) is maintained, so that a class is only
+// loaded once.
+//
+// It may happen that the weak reference to the ClassLoader becomes null while
+// the reference to the Class remains non-null (in case the Class was actually
+// loaded by some parent of the ClassLoader), in which case the ClassLoader is
+// resurrected (which cannot cause any classes to be loaded multiple times, as
+// the ClassLoader is no longer reachable, so no classes it has ever loaded are
+// still reachable).
+//
+// Similarly, it may happen that the weak reference to the Class becomes null
+// while the reference to the ClassLoader remains non-null, in which case the
+// Class is simply re-loaded.
+//
+// This code is close to the implementation of jvmaccess::ClassPath::loadClass
+// in jvmaccess/classpath.hxx, but not close enough to avoid the duplication.
+//
+// If false is returned, a (still pending) JNI exception occurred.
+bool loadClass(
+ Reference< XComponentContext > const & context, JNIEnv& environment,
+ OUString const & classPath, OUString const & name,
+ LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr)
+{
+ OSL_ASSERT(classLoaderPtr != nullptr);
+ // For any jweak entries still present in the map upon destruction,
+ // DeleteWeakGlobalRef is not called (which is a leak):
+ static ClassMapData classMapData;
+ osl::MutexGuard g(classMapData.mutex);
+ ClassMap::iterator i(classMapData.map.begin());
+ LocalRef< jobject > cloader(environment);
+ LocalRef< jclass > cl(environment);
+ // Prune dangling weak references from the list while searching for a match,
+ // so that the list cannot grow unbounded:
+ for (; i != classMapData.map.end();)
+ {
+ LocalRef< jobject > classLoader( environment );
+ if ( !getLocalFromWeakRef( i->classLoader, classLoader ) )
+ return false;
+
+ LocalRef< jclass > classObject( environment );
+ if ( !getLocalFromWeakRef( i->classObject, classObject ) )
+ return false;
+
+ if ( !classLoader.is() && !classObject.is() )
+ {
+ i = classMapData.map.erase(i);
+ }
+ else if ( i->classPath == classPath && i->className == name )
+ {
+ cloader.set( classLoader.release() );
+ cl.set( classObject.release() );
+ break;
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ if ( !cloader.is() || !cl.is() )
+ {
+ if ( i == classMapData.map.end() )
+ {
+ // Push a new ClassMapEntry (which can potentially fail) before
+ // loading the class, so that it never happens that a class is
+ // loaded but not added to the map (which could have effects on the
+ // JVM that are not easily undone). If the pushed ClassMapEntry is
+ // not used after all (return false, etc.) it will be pruned on next
+ // call because its classLoader/classObject are null:
+ classMapData.map.push_back( ClassMapEntry( classPath, name ) );
+ i = std::prev(classMapData.map.end());
+ }
+
+ LocalRef< jclass > clClass( environment );
+ clClass.set( environment.FindClass( "java/net/URLClassLoader" ) );
+ if ( !clClass.is() )
+ return false;
+
+ jweak wcloader = nullptr;
+ if (!cloader.is())
+ {
+ jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) );
+ if (ctorLoader == nullptr)
+ return false;
+
+ LocalRef< jobjectArray > arr( environment );
+ arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) );
+ if ( !arr.is() )
+ return false;
+
+ jvalue arg;
+ arg.l = arr.get();
+ cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) );
+ if ( !cloader.is() )
+ return false;
+
+ wcloader = environment.NewWeakGlobalRef( cloader.get() );
+ if ( wcloader == nullptr )
+ return false;
+ }
+
+ jweak wcl = nullptr;
+ if ( !cl.is() )
+ {
+ jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) );
+ if ( methLoadClass == nullptr )
+ return false;
+
+ LocalRef< jstring > str( environment );
+ str.set( convertwchar_tToJavaString( &environment, name ) );
+ if ( !str.is() )
+ return false;
+
+ jvalue arg;
+ arg.l = str.get();
+ cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) );
+ if ( !cl.is() )
+ return false;
+
+ wcl = environment.NewWeakGlobalRef( cl.get() );
+ if ( wcl == nullptr )
+ return false;
+ }
+
+ if ( wcloader != nullptr)
+ {
+ i->classLoader = wcloader;
+ }
+ if ( wcl != nullptr )
+ {
+ i->classObject = wcl;
+ }
+ }
+
+ classLoaderPtr->set( cloader.release() );
+ classPtr->set( cl.release() );
+ return true;
+}
+
+}
+
+
+IMPLEMENT_SERVICE_INFO(java_sql_Connection,"com.sun.star.sdbcx.JConnection","com.sun.star.sdbc.Connection");
+
+
+//************ Class: java.sql.Connection
+
+jclass java_sql_Connection::theClass = nullptr;
+
+java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver )
+ :m_xContext( _rDriver.getContext() )
+ ,m_pDriver( &_rDriver )
+ ,m_pDriverobject(nullptr)
+ ,m_Driver_theClass(nullptr)
+ ,m_aLogger( _rDriver.getLogger() )
+ ,m_bIgnoreDriverPrivileges(true)
+ ,m_bIgnoreCurrency(false)
+{
+}
+
+java_sql_Connection::~java_sql_Connection()
+{
+ ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM();
+ if ( !xTest.is() )
+ return;
+
+ SDBThreadAttach t;
+ clearObject(*t.pEnv);
+
+ {
+ if ( m_pDriverobject )
+ t.pEnv->DeleteGlobalRef( m_pDriverobject );
+ m_pDriverobject = nullptr;
+ if ( m_Driver_theClass )
+ t.pEnv->DeleteGlobalRef( m_Driver_theClass );
+ m_Driver_theClass = nullptr;
+ }
+ SDBThreadAttach::releaseRef();
+}
+
+void java_sql_Connection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION );
+
+ java_sql_Connection_BASE::disposing();
+
+ if ( object )
+ {
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("close", mID);
+ }
+}
+
+jclass java_sql_Connection::getMyClass() const
+{
+ // the class must be fetched only once, therefore static
+ if( !theClass )
+ theClass = findMyClass("java/sql/Connection");
+ return theClass;
+}
+
+
+OUString SAL_CALL java_sql_Connection::getCatalog( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ static jmethodID mID(nullptr);
+ return callStringMethod("getCatalog",mID);
+}
+
+Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID);
+ if(out)
+ {
+ xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this );
+ m_xMetaData = xMetaData;
+ }
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL java_sql_Connection::close( )
+{
+ dispose();
+}
+
+void SAL_CALL java_sql_Connection::commit( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("commit", mID);
+}
+
+sal_Bool SAL_CALL java_sql_Connection::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed;
+}
+
+sal_Bool SAL_CALL java_sql_Connection::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "isReadOnly", mID );
+}
+
+void SAL_CALL java_sql_Connection::setCatalog( const OUString& catalog )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithStringArg("setCatalog",mID,catalog);
+}
+
+void SAL_CALL java_sql_Connection::rollback( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("rollback", mID);
+}
+
+sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( )
+{
+ static jmethodID mID(nullptr);
+ return callBooleanMethod( "getAutoCommit", mID );
+}
+
+void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithBoolArg_ThrowSQL("setReadOnly", mID, readOnly);
+}
+
+void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethodWithBoolArg_ThrowSQL("setAutoCommit", mID, autoCommit);
+}
+
+Reference< css::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ static jmethodID mID(nullptr);
+ callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID);
+ // WARNING: the caller becomes the owner of the returned pointer
+ return nullptr;
+}
+
+void SAL_CALL java_sql_Connection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
+}
+
+
+sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ static jmethodID mID(nullptr);
+ return callIntMethod_ThrowSQL("getTransactionIsolation", mID);
+}
+
+void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ static jmethodID mID(nullptr);
+ callVoidMethodWithIntArg_ThrowSQL("setTransactionIsolation", mID, level);
+}
+
+Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT );
+
+ SDBThreadAttach t;
+ rtl::Reference<java_sql_Statement> pStatement = new java_sql_Statement( t.pEnv, *this );
+ Reference< XStatement > xStmt = pStatement;
+ m_aStatements.push_back( WeakReferenceHelper( xStmt ) );
+
+ m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() );
+ return xStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
+
+ SDBThreadAttach t;
+
+ rtl::Reference<java_sql_PreparedStatement> pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sql );
+ Reference< XPreparedStatement > xReturn( pStatement );
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+
+ m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() );
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+ m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql );
+
+ SDBThreadAttach t;
+
+ rtl::Reference<java_sql_CallableStatement> pStatement = new java_sql_CallableStatement( t.pEnv, *this, sql );
+ Reference< XPreparedStatement > xStmt( pStatement );
+ m_aStatements.push_back(WeakReferenceHelper(xStmt));
+
+ m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() );
+ return xStmt;
+}
+
+OUString SAL_CALL java_sql_Connection::nativeSQL( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ OUString aStr;
+ SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!");
+ {
+
+ // initialize temporary Variable
+ static const char * const cSignature = "(Ljava/lang/String;)Ljava/lang/String;";
+ static const char * const cMethodName = "nativeSQL";
+ // Java-Call
+ static jmethodID mID(nullptr);
+ obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
+ // Convert Parameter
+ jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql));
+
+ jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() );
+ aStr = JavaString2String(t.pEnv, static_cast<jstring>(out) );
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ } //t.pEnv
+
+ m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr );
+
+ return aStr;
+}
+
+void SAL_CALL java_sql_Connection::clearWarnings( )
+{
+ static jmethodID mID(nullptr);
+ callVoidMethod_ThrowSQL("clearWarnings", mID);
+}
+
+Any SAL_CALL java_sql_Connection::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
+
+ SDBThreadAttach t;
+ static jmethodID mID(nullptr);
+ jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
+ // WARNING: the caller becomes the owner of the returned pointer
+ if( out )
+ {
+ java_sql_SQLWarning_BASE warn_base(t.pEnv, out);
+ SQLException aAsException( java_sql_SQLWarning( warn_base, *this ) );
+
+ // translate to warning
+ SQLWarning aWarning;
+ aWarning.Context = aAsException.Context;
+ aWarning.Message = aAsException.Message;
+ aWarning.SQLState = aAsException.SQLState;
+ aWarning.ErrorCode = aAsException.ErrorCode;
+ aWarning.NextException = aAsException.NextException;
+
+ return Any( aWarning );
+ }
+
+ return Any();
+}
+
+
+namespace
+{
+ OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const OUString& _rDriverClass, const OUString& _rDriverClassPath )
+ {
+ OUString sError1( _aResource.getResourceStringWithSubstitution(
+ STR_NO_CLASSNAME,
+ "$classname$", _rDriverClass
+ ) );
+ if ( !_rDriverClassPath.isEmpty() )
+ {
+ const OUString sError2( _aResource.getResourceStringWithSubstitution(
+ STR_NO_CLASSNAME_PATH,
+ "$classpath$", _rDriverClassPath
+ ) );
+ sError1 += sError2;
+ } // if ( _rDriverClassPath.getLength() )
+ return sError1;
+ }
+}
+
+
+namespace
+{
+ bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger,
+ JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties )
+ {
+ if ( !_rSystemProperties.hasElements() )
+ // nothing to do
+ return true;
+
+ LocalRef< jclass > systemClass( _rEnv );
+ jmethodID nSetPropertyMethodID = nullptr;
+ // retrieve the java.lang.System class
+ systemClass.set( _rEnv.FindClass( "java/lang/System" ) );
+ if ( systemClass.is() )
+ {
+ nSetPropertyMethodID = _rEnv.GetStaticMethodID(
+ systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
+ }
+
+ if ( nSetPropertyMethodID == nullptr )
+ return false;
+
+ for ( auto const & systemProp : _rSystemProperties )
+ {
+ OUString sValue;
+ OSL_VERIFY( systemProp.Value >>= sValue );
+
+ _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, systemProp.Name, sValue );
+
+ LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, systemProp.Name ) );
+ LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) );
+
+ _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() );
+ LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() );
+ if ( throwable.is() )
+ return false;
+ }
+
+ return true;
+ }
+}
+
+
+void java_sql_Connection::loadDriverFromProperties( const OUString& _sDriverClass, const OUString& _sDriverClassPath,
+ const Sequence< NamedValue >& _rSystemProperties )
+{
+ // first try if the jdbc driver is already registered at the driver manager
+ SDBThreadAttach t;
+ try
+ {
+ if ( !object )
+ {
+ if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) )
+ ThrowLoggedSQLException( getLogger(), t.pEnv, *this );
+
+ m_pDriverClassLoader.reset();
+
+ // here I try to find the class for jdbc driver
+ java_sql_SQLException_BASE::st_getMyClass();
+ java_lang_Throwable::st_getMyClass();
+
+ if ( _sDriverClass.isEmpty() )
+ {
+ m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS );
+ ::dbtools::throwGenericSQLException(
+ lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
+ *this
+ );
+ }
+ else
+ {
+ m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass );
+ // the driver manager holds the class of the driver for later use
+ std::unique_ptr< java_lang_Class > pDrvClass;
+ if ( _sDriverClassPath.isEmpty() )
+ {
+ // if forName didn't find the class it will throw an exception
+ pDrvClass.reset(java_lang_Class::forName(_sDriverClass));
+ }
+ else
+ {
+ LocalRef< jclass > driverClass(t.env());
+ LocalRef< jobject > driverClassLoader(t.env());
+
+ loadClass(
+ m_pDriver->getContext(),
+ t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass );
+
+ m_pDriverClassLoader.set( driverClassLoader );
+ pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) );
+
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+ if (pDrvClass)
+ {
+ LocalRef< jobject > driverObject( t.env() );
+ driverObject.set( pDrvClass->newInstanceObject() );
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ m_pDriverobject = driverObject.release();
+
+ if( m_pDriverobject )
+ m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject );
+
+ {
+ jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject);
+ if ( m_pDriverobject )
+ {
+ m_Driver_theClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass ));
+ t.pEnv->DeleteLocalRef( tempClass );
+ }
+ }
+ }
+ m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS );
+ }
+ }
+ }
+ catch( const SQLException& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw SQLException(
+ lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
+ *this,
+ OUString(),
+ 1000,
+ anyEx);
+ }
+ catch( Exception& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ ::dbtools::throwGenericSQLException(
+ lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
+ *this,
+ anyEx
+ );
+ }
+}
+
+OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass)
+{
+ static constexpr OUStringLiteral s_sNodeName
+ = u"org.openoffice.Office.DataAccess/JDBC/DriverClassPaths";
+ ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ m_pDriver->getContext(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
+ OUString sURL;
+ if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) )
+ {
+ ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass );
+ OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL );
+ }
+ return sURL;
+}
+
+bool java_sql_Connection::construct(const OUString& url,
+ const Sequence< PropertyValue >& info)
+{
+ { // initialize the java vm
+ ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(m_xContext);
+ if ( !xTest.is() )
+ throwGenericSQLException(STR_NO_JAVA,*this);
+ }
+ SDBThreadAttach t;
+ SDBThreadAttach::addRef(); // will be released in dtor
+ if ( !t.pEnv )
+ throwGenericSQLException(STR_NO_JAVA,*this);
+
+ OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
+ bool bAutoRetrievingEnabled = false; // set to <TRUE/> when we should allow to query for generated values
+ OUString sDriverClassPath,sDriverClass;
+ Sequence< NamedValue > aSystemProperties;
+
+ ::comphelper::NamedValueCollection aSettings( info );
+ sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass );
+ sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath);
+ if ( sDriverClassPath.isEmpty() )
+ sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
+ bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
+ sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
+ m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
+ m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
+ aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
+ m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() );
+ m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() );
+
+ loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties );
+
+ enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
+ setAutoRetrievingStatement(sGeneratedValueStatement);
+
+ if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
+ {
+ // Java-Call
+ static const char * const cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;";
+ static const char * const cMethodName = "connect";
+ jmethodID mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature );
+
+ if ( mID )
+ {
+ jvalue args[2];
+ // convert Parameter
+ args[0].l = convertwchar_tToJavaString(t.pEnv,url);
+ std::unique_ptr<java_util_Properties> pProps = createStringPropertyArray(info);
+ args[1].l = pProps->getJavaObject();
+
+ LocalRef< jobject > ensureDelete( t.env(), args[0].l );
+
+ jobject out = nullptr;
+ // In some cases (e.g.,
+ // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
+ // l. 249) the JavaDriverClassPath contains multiple jars,
+ // as creating the JavaDriverClass instance requires
+ // (reflective) access to those other jars. Now, if the
+ // JavaDriverClass is actually loaded by some parent class
+ // loader (e.g., because its jar is also on the global
+ // class path), it would still not have access to the
+ // additional jars on the JavaDriverClassPath. Hence, the
+ // JavaDriverClassPath class loader is pushed as context
+ // class loader around the JavaDriverClass instance
+ // creation:
+ // #i82222# / 2007-10-15
+ {
+ ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this );
+ out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l );
+ pProps.reset();
+ ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+ }
+
+ if ( !out )
+ m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION );
+
+ if ( out )
+ object = t.pEnv->NewGlobalRef( out );
+
+ if ( object )
+ m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url );
+
+ m_aConnectionInfo = info;
+ } //mID
+ } //t.pEnv
+ return object != nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */