| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_connectivity.hxx" |
| |
| #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/lang/DisposedException.hpp> |
| #include <com/sun/star/sdbc/SQLWarning.hpp> |
| #include <com/sun/star/sdbc/SQLWarning.hpp> |
| #include <com/sun/star/beans/NamedValue.hpp> |
| #include "connectivity/sqlparse.hxx" |
| #include "connectivity/dbexception.hxx" |
| #include "java/util/Property.hxx" |
| #include "java/LocalRef.hxx" |
| #include "resource/jdbc_log.hrc" |
| #include "com/sun/star/uno/XComponentContext.hpp" |
| #include "jvmaccess/classpath.hxx" |
| #include <comphelper/namedvaluecollection.hxx> |
| #include <rtl/ustrbuf.hxx> |
| #include <jni.h> |
| #include "resource/common_res.hrc" |
| #include <unotools/confignode.hxx> |
| |
| #include <list> |
| #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( |
| rtl::OUString const & theClassPath, rtl::OUString const & theClassName): |
| classPath(theClassPath), className(theClassName), classLoader(NULL), |
| classObject(NULL) {} |
| |
| rtl::OUString classPath; |
| rtl::OUString className; |
| jweak classLoader; |
| jweak classObject; |
| }; |
| |
| typedef std::list< ClassMapEntry > ClassMap; |
| |
| struct ClassMapData { |
| osl::Mutex mutex; |
| |
| ClassMap map; |
| }; |
| |
| struct ClassMapDataInit { |
| ClassMapData * operator()() { |
| static ClassMapData instance; |
| return &instance; |
| } |
| }; |
| |
| 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 != NULL ) |
| { |
| _inout_local.env().DeleteWeakGlobalRef( _weak ); |
| _weak = NULL; |
| } |
| } |
| 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, |
| rtl::OUString const & classPath, rtl::OUString const & name, |
| LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr) |
| { |
| OSL_ASSERT(classLoaderPtr != NULL); |
| // For any jweak entries still present in the map upon destruction, |
| // DeleteWeakGlobalRef is not called (which is a leak): |
| ClassMapData * d = |
| rtl_Instance< ClassMapData, ClassMapDataInit, osl::MutexGuard, |
| osl::GetGlobalMutex >::create( |
| ClassMapDataInit(), osl::GetGlobalMutex()); |
| osl::MutexGuard g(d->mutex); |
| ClassMap::iterator i(d->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 != d->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 = d->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 == d->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: |
| d->map.push_front( ClassMapEntry( classPath, name ) ); |
| i = d->map.begin(); |
| } |
| |
| LocalRef< jclass > clClass( environment ); |
| clClass.set( environment.FindClass( "java/net/URLClassLoader" ) ); |
| if ( !clClass.is() ) |
| return false; |
| |
| jweak wcloader = NULL; |
| if (!cloader.is()) |
| { |
| jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) ); |
| if (ctorLoader == NULL) |
| 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 == NULL ) |
| return false; |
| } |
| |
| jweak wcl = NULL; |
| if ( !cl.is() ) |
| { |
| jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) ); |
| if ( methLoadClass == NULL ) |
| 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 == NULL ) |
| return false; |
| } |
| |
| if ( wcloader != NULL) |
| { |
| i->classLoader = wcloader; |
| } |
| if ( wcl != NULL ) |
| { |
| 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 = 0; |
| |
| java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver ) |
| :java_lang_Object( _rDriver.getContext().getLegacyServiceFactory() ) |
| ,OSubComponent<java_sql_Connection, java_sql_Connection_BASE>((::cppu::OWeakObject*)(&_rDriver), this) |
| ,m_pDriver( &_rDriver ) |
| ,m_pDriverobject(NULL) |
| ,m_pDriverClassLoader() |
| ,m_Driver_theClass(NULL) |
| ,m_aLogger( _rDriver.getLogger() ) |
| ,m_bParameterSubstitution(sal_False) |
| ,m_bIgnoreDriverPrivileges(sal_True) |
| ,m_bIgnoreCurrency(sal_False) |
| { |
| } |
| // ----------------------------------------------------------------------------- |
| java_sql_Connection::~java_sql_Connection() |
| { |
| ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(); |
| if ( xTest.is() ) |
| { |
| SDBThreadAttach t; |
| clearObject(*t.pEnv); |
| |
| { |
| if ( m_pDriverobject ) |
| t.pEnv->DeleteGlobalRef( m_pDriverobject ); |
| m_pDriverobject = NULL; |
| if ( m_Driver_theClass ) |
| t.pEnv->DeleteGlobalRef( m_Driver_theClass ); |
| m_Driver_theClass = NULL; |
| } |
| t.releaseRef(); |
| } |
| } |
| //----------------------------------------------------------------------------- |
| void SAL_CALL java_sql_Connection::release() throw() |
| { |
| relase_ChildImpl(); |
| } |
| //------------------------------------------------------------------------------ |
| void java_sql_Connection::disposing() |
| { |
| ::osl::MutexGuard aGuard(m_aMutex); |
| |
| m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION ); |
| |
| dispose_ChildImpl(); |
| java_sql_Connection_BASE::disposing(); |
| |
| if ( object ) |
| { |
| static jmethodID mID(NULL); |
| callVoidMethod("close",mID); |
| } |
| } |
| // ------------------------------------------------------------------------- |
| jclass java_sql_Connection::getMyClass() const |
| { |
| // die Klasse muss nur einmal geholt werden, daher statisch |
| if( !theClass ) |
| theClass = findMyClass("java/sql/Connection"); |
| return theClass; |
| } |
| |
| // ------------------------------------------------------------------------- |
| ::rtl::OUString SAL_CALL java_sql_Connection::getCatalog( ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| |
| static jmethodID mID(NULL); |
| return callStringMethod("getCatalog",mID); |
| } |
| // ------------------------------------------------------------------------- |
| Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( ) throw(SQLException, RuntimeException) |
| { |
| ::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 Enviroment geloescht worden!"); |
| static jmethodID mID(NULL); |
| 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( ) throw(SQLException, RuntimeException) |
| { |
| dispose(); |
| } |
| // ------------------------------------------------------------------------- |
| void SAL_CALL java_sql_Connection::commit( ) throw(SQLException, RuntimeException) |
| { |
| static jmethodID mID(NULL); |
| callVoidMethod("commit",mID); |
| } |
| // ------------------------------------------------------------------------- |
| sal_Bool SAL_CALL java_sql_Connection::isClosed( ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| |
| static jmethodID mID(NULL); |
| return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed; |
| } |
| // ------------------------------------------------------------------------- |
| sal_Bool SAL_CALL java_sql_Connection::isReadOnly( ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| static jmethodID mID(NULL); |
| return callBooleanMethod( "isReadOnly", mID ); |
| } |
| // ------------------------------------------------------------------------- |
| void SAL_CALL java_sql_Connection::setCatalog( const ::rtl::OUString& catalog ) throw(SQLException, RuntimeException) |
| { |
| static jmethodID mID(NULL); |
| callVoidMethodWithStringArg("setCatalog",mID,catalog); |
| } |
| // ------------------------------------------------------------------------- |
| void SAL_CALL java_sql_Connection::rollback( ) throw(SQLException, RuntimeException) |
| { |
| static jmethodID mID(NULL); |
| callVoidMethod("rollback",mID); |
| } |
| // ------------------------------------------------------------------------- |
| sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( ) throw(SQLException, RuntimeException) |
| { |
| static jmethodID mID(NULL); |
| return callBooleanMethod( "getAutoCommit", mID ); |
| } |
| // ------------------------------------------------------------------------- |
| void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly ) throw(SQLException, RuntimeException) |
| { |
| static jmethodID mID(NULL); |
| callVoidMethodWithBoolArg("setReadOnly",mID,readOnly); |
| } |
| // ------------------------------------------------------------------------- |
| void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException) |
| { |
| static jmethodID mID(NULL); |
| callVoidMethodWithBoolArg("setAutoCommit",mID,autoCommit); |
| } |
| // ------------------------------------------------------------------------- |
| Reference< ::com::sun::star::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| |
| SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!"); |
| static jmethodID mID(NULL); |
| /*jobject out = */callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID); |
| // ACHTUNG: der Aufrufer wird Eigentuemer des zurueckgelieferten Zeigers !!! |
| return 0;// ? 0 : Map2XNameAccess( t.pEnv, out ); |
| } |
| // ------------------------------------------------------------------------- |
| void SAL_CALL java_sql_Connection::setTypeMap( const Reference< ::com::sun::star::container::XNameAccess >& /*typeMap*/ ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| |
| ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this ); |
| } |
| |
| // ------------------------------------------------------------------------- |
| sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| |
| static jmethodID mID(NULL); |
| return callIntMethod("getTransactionIsolation",mID); |
| } |
| // ------------------------------------------------------------------------- |
| void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| |
| static jmethodID mID(NULL); |
| callVoidMethodWithIntArg("setTransactionIsolation",mID,level); |
| } |
| // ------------------------------------------------------------------------- |
| Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT ); |
| |
| SDBThreadAttach t; |
| 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; |
| } |
| // ----------------------------------------------------------------------------- |
| ::rtl::OUString java_sql_Connection::transFormPreparedStatement(const ::rtl::OUString& _sSQL) |
| { |
| ::rtl::OUString sSqlStatement = _sSQL; |
| if ( m_bParameterSubstitution ) |
| { |
| try |
| { |
| OSQLParser aParser( m_pDriver->getContext().getLegacyServiceFactory() ); |
| ::rtl::OUString sErrorMessage; |
| ::rtl::OUString sNewSql; |
| OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL); |
| if(pNode) |
| { // special handling for parameters |
| OSQLParseNode::substituteParameterNames(pNode); |
| pNode->parseNodeToStr( sNewSql, this ); |
| delete pNode; |
| sSqlStatement = sNewSql; |
| } |
| } |
| catch(const Exception&) |
| { |
| } |
| } |
| return sSqlStatement; |
| } |
| // ------------------------------------------------------------------------- |
| Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) |
| { |
| ::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::OUString sSqlStatement = sql; |
| sSqlStatement = transFormPreparedStatement( sSqlStatement ); |
| |
| java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sSqlStatement ); |
| 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 ::rtl::OUString& sql ) throw(SQLException, RuntimeException) |
| { |
| ::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::OUString sSqlStatement = sql; |
| sSqlStatement = transFormPreparedStatement( sSqlStatement ); |
| |
| java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sSqlStatement ); |
| Reference< XPreparedStatement > xStmt( pStatement ); |
| m_aStatements.push_back(WeakReferenceHelper(xStmt)); |
| |
| m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() ); |
| return xStmt; |
| } |
| // ------------------------------------------------------------------------- |
| ::rtl::OUString SAL_CALL java_sql_Connection::nativeSQL( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| |
| ::rtl::OUString aStr; |
| SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!"); |
| { |
| |
| // temporaere Variable initialisieren |
| static const char * cSignature = "(Ljava/lang/String;)Ljava/lang/String;"; |
| static const char * cMethodName = "nativeSQL"; |
| // Java-Call absetzen |
| static jmethodID mID(NULL); |
| obtainMethodId(t.pEnv, cMethodName,cSignature, mID); |
| // Parameter konvertieren |
| jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql)); |
| |
| jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() ); |
| aStr = JavaString2String(t.pEnv, (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( ) throw(SQLException, RuntimeException) |
| { |
| static jmethodID mID(NULL); |
| callVoidMethod("clearWarnings",mID); |
| } |
| // ------------------------------------------------------------------------- |
| Any SAL_CALL java_sql_Connection::getWarnings( ) throw(SQLException, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); |
| |
| SDBThreadAttach t; |
| static jmethodID mID(NULL); |
| jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID); |
| // ACHTUNG: der Aufrufer wird Eigentuemer des zurueckgelieferten Zeigers !!! |
| if( out ) |
| { |
| java_sql_SQLWarning_BASE warn_base(t.pEnv, out); |
| SQLException aAsException( static_cast< starsdbc::SQLException >( 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 makeAny( aWarning ); |
| } |
| |
| return Any(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| namespace |
| { |
| ::rtl::OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const ::rtl::OUString& _rDriverClass, const ::rtl::OUString& _rDriverClassPath ) |
| { |
| ::rtl::OUString sError1( _aResource.getResourceStringWithSubstitution( |
| STR_NO_CLASSNAME, |
| "$classname$", _rDriverClass |
| ) ); |
| if ( _rDriverClassPath.getLength() ) |
| { |
| const ::rtl::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.getLength() == 0 ) |
| // nothing to do |
| return true; |
| |
| LocalRef< jclass > systemClass( _rEnv ); |
| jmethodID nSetPropertyMethodID = 0; |
| // 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 == 0 ) |
| return false; |
| |
| for ( const NamedValue* pSystemProp = _rSystemProperties.getConstArray(); |
| pSystemProp != _rSystemProperties.getConstArray() + _rSystemProperties.getLength(); |
| ++pSystemProp |
| ) |
| { |
| ::rtl::OUString sValue; |
| OSL_VERIFY( pSystemProp->Value >>= sValue ); |
| |
| _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, pSystemProp->Name, sValue ); |
| |
| LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, pSystemProp->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 ::rtl::OUString& _sDriverClass, const ::rtl::OUString& _sDriverClassPath, |
| const Sequence< NamedValue >& _rSystemProperties ) |
| { |
| // contains the statement which should be used when query for automatically generated values |
| ::rtl::OUString sGeneratedValueStatement; |
| // set to <TRUE/> when we should allow to query for generated values |
| sal_Bool bAutoRetrievingEnabled = sal_False; |
| |
| // first try if the jdbc driver is alraedy 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.getLength() ) |
| { |
| 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::auto_ptr< java_lang_Class > pDrvClass; |
| if ( !_sDriverClassPath.getLength() ) |
| { |
| // if forName didn't find the class it will throw an exception |
| pDrvClass = ::std::auto_ptr< java_lang_Class >(java_lang_Class::forName(_sDriverClass)); |
| } |
| else |
| { |
| LocalRef< jclass > driverClass(t.env()); |
| LocalRef< jobject > driverClassLoader(t.env()); |
| |
| loadClass( |
| m_pDriver->getContext().getUNOContext(), |
| 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.get() ) |
| { |
| LocalRef< jobject > driverObject( t.env() ); |
| driverObject.set( pDrvClass->newInstanceObject() ); |
| ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); |
| m_pDriverobject = driverObject.release(); |
| |
| if( t.pEnv && m_pDriverobject ) |
| m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject ); |
| |
| { |
| jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject); |
| if ( m_pDriverobject ) |
| { |
| m_Driver_theClass = (jclass)t.pEnv->NewGlobalRef( tempClass ); |
| t.pEnv->DeleteLocalRef( tempClass ); |
| } |
| } |
| } |
| m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS ); |
| } |
| } |
| } |
| catch( const SQLException& e ) |
| { |
| throw SQLException( |
| lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ), |
| *this, |
| ::rtl::OUString(), |
| 1000, |
| makeAny(e) |
| ); |
| } |
| catch( Exception& ) |
| { |
| ::dbtools::throwGenericSQLException( |
| lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ), |
| *this |
| ); |
| } |
| |
| enableAutoRetrievingEnabled( bAutoRetrievingEnabled ); |
| setAutoRetrievingStatement( sGeneratedValueStatement ); |
| } |
| // ----------------------------------------------------------------------------- |
| ::rtl::OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const ::rtl::OUString& _sDriverClass) |
| { |
| static const ::rtl::OUString s_sNodeName(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.Office.DataAccess/JDBC/DriverClassPaths")); |
| ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithServiceFactory( |
| m_pDriver->getContext().getLegacyServiceFactory(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY); |
| ::rtl::OUString sURL; |
| if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) ) |
| { |
| ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass ); |
| OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL ); |
| } |
| return sURL; |
| } |
| // ----------------------------------------------------------------------------- |
| sal_Bool java_sql_Connection::construct(const ::rtl::OUString& url, |
| const Sequence< PropertyValue >& info) |
| { |
| { // initialize the java vm |
| ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(getORB()); |
| if ( !xTest.is() ) |
| throwGenericSQLException(STR_NO_JAVA,*this); |
| } |
| SDBThreadAttach t; |
| t.addRef(); // will be released in dtor |
| if ( !t.pEnv ) |
| throwGenericSQLException(STR_NO_JAVA,*this); |
| |
| ::rtl::OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values |
| sal_Bool bAutoRetrievingEnabled = sal_False; // set to <TRUE/> when we should allow to query for generated values |
| ::rtl::OUString sDriverClassPath,sDriverClass; |
| Sequence< NamedValue > aSystemProperties; |
| |
| ::comphelper::NamedValueCollection aSettings( info ); |
| sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass ); |
| sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath); |
| if ( !sDriverClassPath.getLength() ) |
| sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass); |
| bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled ); |
| sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement ); |
| m_bParameterSubstitution = aSettings.getOrDefault( "ParameterNameSubstitution", m_bParameterSubstitution ); |
| 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 ) |
| { |
| // temporaere Variable initialisieren |
| static const char * cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;"; |
| static const char * cMethodName = "connect"; |
| // Java-Call absetzen |
| jmethodID mID = NULL; |
| if ( !mID ) |
| mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature ); |
| if ( mID ) |
| { |
| jvalue args[2]; |
| // Parameter konvertieren |
| args[0].l = convertwchar_tToJavaString(t.pEnv,url); |
| java_util_Properties* pProps = createStringPropertyArray(info); |
| args[1].l = pProps->getJavaObject(); |
| |
| LocalRef< jobject > ensureDelete( t.env(), args[0].l ); |
| |
| jobject out = NULL; |
| // 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 ); |
| delete pProps, pProps = NULL; |
| 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 != NULL; |
| } |
| // ----------------------------------------------------------------------------- |