diff options
Diffstat (limited to '')
-rw-r--r-- | connectivity/source/drivers/jdbc/JConnection.cxx | 803 |
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: */ |