Tag: cws_src680_dba24c User: fs Date: 2007-10-15 13:33:17+0000 Modified: dba/connectivity/source/drivers/jdbc/JConnection.cxx
Log: #i82222# reworked SBs patch to use the driver classes class loader when constructing the connection, not when actually loading the system driver File Changes: Directory: /dba/connectivity/source/drivers/jdbc/ ================================================= File [changed]: JConnection.cxx Url: http://dba.openoffice.org/source/browse/dba/connectivity/source/drivers/jdbc/JConnection.cxx?r1=1.6.2.2&r2=1.6.2.3 Delta lines: +161 -265 ----------------------- --- JConnection.cxx 2007-10-10 20:40:46+0000 1.6.2.2 +++ JConnection.cxx 2007-10-15 13:33:15+0000 1.6.2.3 @@ -4,9 +4,9 @@ * * $RCSfile: JConnection.cxx,v $ * - * $Revision: 1.6.2.2 $ + * $Revision: 1.6.2.3 $ * - * last change: $Author: fs $ $Date: 2007/10/10 20:40:46 $ + * last change: $Author: fs $ $Date: 2007/10/15 13:33:15 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -35,13 +35,12 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_connectivity.hxx" -#ifndef _CONNECTIVITY_JAVA_SQL_CONNECTION_HXX_ + #include "java/sql/Connection.hxx" -#endif #include "java/lang/Class.hxx" -#ifndef _CONNECTIVITY_JAVA_TOOLS_HXX_ #include "java/tools.hxx" -#endif +#include "java/ContextClassLoader.hxx" + #ifndef _CONNECTIVITY_JAVA_SQL_DATABASEMETADATA_HXX_ #include "java/sql/DatabaseMetaData.hxx" #endif @@ -83,6 +82,7 @@ #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; @@ -91,27 +91,6 @@ namespace { -template< typename T > struct LocalRef { - explicit LocalRef(JNIEnv * environment): - object(NULL), m_environment(environment) {} - - ~LocalRef() { if (object != NULL) m_environment->DeleteLocalRef(object); } - - T release() { - T t = object; - object = NULL; - return t; - } - - T object; - -private: - LocalRef(LocalRef &); // not defined - void operator =(LocalRef &); // not defined - - JNIEnv *& m_environment; -}; - struct ClassMapEntry { ClassMapEntry( rtl::OUString const & theClassPath, rtl::OUString const & theClassName): @@ -139,6 +118,26 @@ } }; +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. @@ -159,7 +158,7 @@ // // If false is returned, a (still pending) JNI exception occurred. bool loadClass( - Reference< XComponentContext > const & context, JNIEnv * environment, + Reference< XComponentContext > const & context, JNIEnv& environment, rtl::OUString const & classPath, rtl::OUString const & name, LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr) { @@ -176,164 +175,111 @@ 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 > ocloader(environment); - ocloader.object = environment->NewLocalRef(i->classLoader); - if (ocloader.object == NULL) { - if (environment->ExceptionCheck()) { + for (; i != d->map.end();) + { + LocalRef< jobject > classLoader( environment ); + if ( !getLocalFromWeakRef( i->classLoader, classLoader ) ) return false; - } else if (i->classLoader != NULL) { - environment->DeleteWeakGlobalRef(i->classLoader); - i->classLoader = NULL; - } - } - LocalRef< jclass > ocl(environment); - ocl.object = static_cast< jclass >( - environment->NewLocalRef(i->classObject)); - if (ocl.object == NULL) { - if (environment->ExceptionCheck()) { + + LocalRef< jclass > classObject( environment ); + if ( !getLocalFromWeakRef( i->classObject, classObject ) ) return false; - } else if (i->classObject != NULL) { - environment->DeleteWeakGlobalRef(i->classObject); - i->classObject = NULL; - } - } - if (ocloader.object == NULL && ocl.object == NULL) { + + if ( !classLoader.is() && !classObject.is() ) + { i = d->map.erase(i); - } else if (i->classPath == classPath && i->className == name) { - cloader.object = ocloader.release(); - cl.object = ocl.release(); + } + else if ( i->classPath == classPath && i->className == name ) + { + cloader.set( classLoader.release() ); + cl.set( classObject.release() ); break; - } else { + } + else + { ++i; } } - if (cloader.object == NULL || cl.object == NULL) { - if (i == d->map.end()) { + 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)); + d->map.push_front( ClassMapEntry( classPath, name ) ); i = d->map.begin(); } - LocalRef< jclass > clClass(environment); - clClass.object = environment->FindClass("java/net/URLClassLoader"); - if (clClass.object == NULL) { + + LocalRef< jclass > clClass( environment ); + clClass.set( environment.FindClass( "java/net/URLClassLoader" ) ); + if ( !clClass.is() ) return false; - } + jweak wcloader = NULL; - if (cloader.object == NULL) { - jmethodID ctorLoader( - environment->GetMethodID( - clClass.object, "<init>", "([Ljava/net/URL;)V")); - if (ctorLoader == 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.object = jvmaccess::ClassPath::translateToUrls( - context, environment, classPath); - if (arr.object == NULL) { + + LocalRef< jobjectArray > arr( environment ); + arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) ); + if ( !arr.is() ) return false; - } + jvalue arg; - arg.l = arr.object; - cloader.object = environment->NewObjectA( - clClass.object, ctorLoader, &arg); - if (cloader.object == NULL) { + arg.l = arr.get(); + cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) ); + if ( !cloader.is() ) return false; - } - wcloader = environment->NewWeakGlobalRef(cloader.object); - if (wcloader == NULL) { + + wcloader = environment.NewWeakGlobalRef( cloader.get() ); + if ( wcloader == NULL ) return false; } - } + jweak wcl = NULL; - if (cl.object == NULL) { - jmethodID methLoadClass( - environment->GetMethodID( - clClass.object, "loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;")); - if (methLoadClass == 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.object = environment->NewString( - static_cast< jchar const * >(name.getStr()), - static_cast< jsize >(name.getLength())); - if (str.object == NULL) { + + LocalRef< jstring > str( environment ); + str.set( convertwchar_tToJavaString( &environment, name ) ); + if ( !str.is() ) return false; - } + jvalue arg; - arg.l = str.object; - cl.object = static_cast< jclass > ( - environment->CallObjectMethodA( - cloader.object, methLoadClass, &arg)); - if (cl.object == NULL) { + arg.l = str.get(); + cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) ); + if ( !cl.is() ) return false; - } - wcl = environment->NewWeakGlobalRef(cl.object); - if (wcl == NULL) { + + wcl = environment.NewWeakGlobalRef( cl.get() ); + if ( wcl == NULL ) return false; } - } - if (wcloader != NULL) { + + if ( wcloader != NULL) + { i->classLoader = wcloader; } - if (wcl != NULL) { + if ( wcl != NULL ) + { i->classObject = wcl; } } - classLoaderPtr->object = cloader.release(); - classPtr->object = cl.release(); + + classLoaderPtr->set( cloader.release() ); + classPtr->set( cl.release() ); return true; } -// simulate a Java -// finally { -// Thread.currentThread.setContextClassLoader(oldContextClassLoader); } -class ContextClassLoaderScope { -public: - ContextClassLoaderScope( - JNIEnv * environment, LocalRef< jobject > & currentThread, - LocalRef< jobject > & oldContextClassLoader): - m_environment(environment), m_currentThread(currentThread), - m_oldContextClassLoader(oldContextClassLoader), m_active(false) {} - - ~ContextClassLoaderScope() { pop(true); } - - void activate(jmethodID setContextClassLoaderMethod) { - m_setContextClassLoaderMethod = setContextClassLoaderMethod; - m_active = true; - } - - void pop() { pop(false); } - -private: - ContextClassLoaderScope(ContextClassLoaderScope &); // not defined - void operator =(ContextClassLoaderScope &); // not defined - - void pop(bool clearExceptions) { - if (m_active) { - m_active = false; - m_environment->CallObjectMethod( - m_currentThread.object, m_setContextClassLoaderMethod, - m_oldContextClassLoader.object); - if (clearExceptions) { - m_environment->ExceptionClear(); - } - } - } - - JNIEnv *& m_environment; - LocalRef< jobject > & m_currentThread; - LocalRef< jobject > & m_oldContextClassLoader; - jmethodID m_setContextClassLoaderMethod; - bool m_active; -}; - } //------------------------------------------------------------------------------ @@ -350,6 +296,7 @@ ,m_xMetaData(NULL) ,m_pDriver( &_rDriver ) ,m_pDriverobject(NULL) + ,m_pDriverClassLoader() ,m_Driver_theClass(NULL) ,m_aLogger( _rDriver.getLogger() ) ,m_bParameterSubstitution(sal_False) @@ -960,12 +907,15 @@ return Any(); } // ----------------------------------------------------------------------------- -void java_sql_Connection::loadDriverFromProperties( - const Sequence< PropertyValue >& info, ::rtl::OUString& _rsGeneratedValueStatement, - sal_Bool& _rbAutoRetrievingEnabled, sal_Bool& _bParameterSubstitution, sal_Bool& _bIgnoreDriverPrivileges ) +void java_sql_Connection::loadDriverFromProperties( const Sequence< PropertyValue >& info ) { + // 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; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!"); + SDBThreadAttach t; try { const PropertyValue* pJavaDriverClass = 0; @@ -984,23 +934,25 @@ } else if(!pBegin->Name.compareToAscii("IsAutoRetrievingEnabled")) { - OSL_VERIFY( pBegin->Value >>= _rbAutoRetrievingEnabled ); + OSL_VERIFY( pBegin->Value >>= bAutoRetrievingEnabled ); } else if(!pBegin->Name.compareToAscii("AutoRetrievingStatement")) { - OSL_VERIFY( pBegin->Value >>= _rsGeneratedValueStatement ); + OSL_VERIFY( pBegin->Value >>= sGeneratedValueStatement ); } else if(!pBegin->Name.compareToAscii("ParameterNameSubstitution")) { - OSL_VERIFY( pBegin->Value >>= _bParameterSubstitution ); + OSL_VERIFY( pBegin->Value >>= m_bParameterSubstitution ); } else if(!pBegin->Name.compareToAscii("IgnoreDriverPrivileges")) { - OSL_VERIFY( pBegin->Value >>= _bIgnoreDriverPrivileges ); + OSL_VERIFY( pBegin->Value >>= m_bIgnoreDriverPrivileges ); } } if ( !object && pJavaDriverClass != 0 ) { + m_pDriverClassLoader.reset(); + // here I try to find the class for jdbc driver java_sql_SQLException_BASE::getMyClass(); java_lang_Throwable::getMyClass(); @@ -1017,7 +969,6 @@ m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, aStr ); // the driver manager holds the class of the driver for later use ::std::auto_ptr< java_lang_Class > pDrvClass; - LocalRef< jobject > classLoader(t.pEnv); if ( pJavaDriverClassPath == 0 ) { // if forName didn't find the class it will throw an exception @@ -1027,94 +978,26 @@ { ::rtl::OUString classpath; OSL_VERIFY( pJavaDriverClassPath->Value >>= classpath ); - LocalRef< jclass > cl(t.pEnv); + + LocalRef< jclass > driverClass(t.env()); + LocalRef< jobject > driverClassLoader(t.env()); + loadClass( m_pDriver->getContext().getUNOContext(), - t.pEnv, classpath, aStr, &classLoader, &cl ); - pDrvClass.reset( - new java_lang_Class( t.pEnv, cl.release() ) - ); + t.env(), classpath, aStr, &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() ) { - // 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: - { - LocalRef< jclass > threadClass(t.pEnv); - LocalRef< jobject > currentThread(t.pEnv); - LocalRef< jobject > oldContextClassLoader(t.pEnv); - ContextClassLoaderScope ccl( - t.pEnv, currentThread, oldContextClassLoader); - if (classLoader.object != NULL) { - threadClass.object = t.pEnv->FindClass( - "java/lang/Thread"); - if (threadClass.object == NULL) { - ThrowLoggedSQLException( - m_aLogger, t.pEnv, *this); - OSL_ASSERT(false); // unreachable - } - jmethodID currentThreadMethod( - t.pEnv->GetStaticMethodID( - threadClass.object, "currentThread", - "()Ljava/lang/Thread;")); - if (currentThreadMethod == NULL) { - ThrowLoggedSQLException( - m_aLogger, t.pEnv, *this); - OSL_ASSERT(false); // unreachable - } - currentThread.object = - t.pEnv->CallStaticObjectMethod( - threadClass.object, currentThreadMethod); - ThrowLoggedSQLException(m_aLogger, t.pEnv, *this); - OSL_ASSERT(currentThread.object != NULL); - jmethodID getContextClassLoaderMethod( - t.pEnv->GetMethodID( - threadClass.object, - "getContextClassLoader", - "()Ljava/lang/ClassLoader;")); - if (getContextClassLoaderMethod == NULL) { - ThrowLoggedSQLException( - m_aLogger, t.pEnv, *this); - OSL_ASSERT(false); // unreachable - } - oldContextClassLoader.object = - t.pEnv->CallObjectMethod( - currentThread.object, - getContextClassLoaderMethod); - ThrowLoggedSQLException(m_aLogger, t.pEnv, *this); - jmethodID setContextClassLoaderMethod( - t.pEnv->GetMethodID( - threadClass.object, - "setContextClassLoader", - "(Ljava/lang/ClassLoader;)V")); - if (setContextClassLoaderMethod == NULL) { - ThrowLoggedSQLException( - m_aLogger, t.pEnv, *this); - OSL_ASSERT(false); // unreachable - } - ccl.activate(setContextClassLoaderMethod); - t.pEnv->CallObjectMethod( - currentThread.object, - setContextClassLoaderMethod, - classLoader.object); - } - LocalRef< jobject > o(t.pEnv); - o.object = pDrvClass->newInstanceObject(); - ccl.pop(); - ThrowLoggedSQLException(m_aLogger, t.pEnv, *this); - m_pDriverobject = o.release(); - } + 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 ); if( t.pEnv ) @@ -1133,13 +1016,24 @@ } catch(SQLException& e) { - throw SQLException(::rtl::OUString::createFromAscii("The specified driver could not be loaded!"),*this,::rtl::OUString(),1000,makeAny(e)); + throw SQLException( + ::rtl::OUString::createFromAscii( "The specified driver could not be loaded." ), + // TODO: resource + *this, + ::rtl::OUString(), + 1000, + makeAny(e) + ); } catch(Exception&) { ::dbtools::throwGenericSQLException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("The specified driver could not be loaded!")) ,*this); } + + enableAutoRetrievingEnabled( bAutoRetrievingEnabled ); + setAutoRetrievingStatement( sGeneratedValueStatement ); } + // ----------------------------------------------------------------------------- sal_Bool java_sql_Connection::construct(const ::rtl::OUString& url, const Sequence< PropertyValue >& info) @@ -1154,12 +1048,7 @@ if ( !t.pEnv ) throw SQLException(::rtl::OUString::createFromAscii("No Java installation could be found. Please check your installation!"),*this,::rtl::OUString::createFromAscii("S1000"),1000 ,Any()); - ::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 - loadDriverFromProperties(info,sGeneratedValueStatement,bAutoRetrievingEnabled,m_bParameterSubstitution,m_bIgnoreDriverPrivileges); - - enableAutoRetrievingEnabled(bAutoRetrievingEnabled); - setAutoRetrievingStatement(sGeneratedValueStatement); + loadDriverFromProperties( info ); if ( t.pEnv && m_Driver_theClass && m_pDriverobject ) { @@ -1179,24 +1068,31 @@ java_util_Properties* pProps = createStringPropertyArray(info); args[1].l = pProps->getJavaObject(); - jobject out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l ); - if ( !out ) - m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION ); + LocalRef< jobject > ensureDelete( t.env(), args[0].l ); - try + 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 ); } - catch(const SQLException& ) - { - t.pEnv->DeleteLocalRef((jstring)args[0].l); - delete pProps; - throw; - } - // und aufraeumen - t.pEnv->DeleteLocalRef((jstring)args[0].l); - delete pProps; - 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 ); --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
