Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <boost/scoped_ptr.hpp>
23 : #include "java/sql/Connection.hxx"
24 : #include "java/lang/Class.hxx"
25 : #include "java/tools.hxx"
26 : #include "java/ContextClassLoader.hxx"
27 : #include "java/sql/DatabaseMetaData.hxx"
28 : #include "java/sql/JStatement.hxx"
29 : #include "java/sql/Driver.hxx"
30 : #include "java/sql/PreparedStatement.hxx"
31 : #include "java/sql/CallableStatement.hxx"
32 : #include "java/sql/SQLWarning.hxx"
33 : #include <com/sun/star/lang/DisposedException.hpp>
34 : #include <com/sun/star/sdbc/SQLWarning.hpp>
35 : #include <com/sun/star/beans/NamedValue.hpp>
36 : #include <connectivity/sqlparse.hxx>
37 : #include <connectivity/dbexception.hxx>
38 : #include "java/util/Property.hxx"
39 : #include "java/LocalRef.hxx"
40 : #include "resource/jdbc_log.hrc"
41 : #include <com/sun/star/uno/XComponentContext.hpp>
42 : #include <jvmaccess/classpath.hxx>
43 : #include <comphelper/namedvaluecollection.hxx>
44 : #include <rtl/ustrbuf.hxx>
45 : #include <jni.h>
46 : #include "resource/common_res.hrc"
47 : #include <unotools/confignode.hxx>
48 :
49 : #include <list>
50 :
51 : using namespace connectivity;
52 : using namespace connectivity::jdbc;
53 : using namespace ::com::sun::star::uno;
54 : using namespace ::com::sun::star::beans;
55 : using namespace ::com::sun::star::sdbc;
56 : using namespace ::com::sun::star::container;
57 : using namespace ::com::sun::star::lang;
58 :
59 : namespace {
60 :
61 12 : struct ClassMapEntry {
62 4 : ClassMapEntry(
63 : OUString const & theClassPath, OUString const & theClassName):
64 : classPath(theClassPath), className(theClassName), classLoader(NULL),
65 4 : classObject(NULL) {}
66 :
67 : OUString classPath;
68 : OUString className;
69 : jweak classLoader;
70 : jweak classObject;
71 : };
72 :
73 : typedef std::list< ClassMapEntry > ClassMap;
74 :
75 8 : struct ClassMapData {
76 : osl::Mutex mutex;
77 :
78 : ClassMap map;
79 : };
80 :
81 : struct ClassMapDataInit {
82 4 : ClassMapData * operator()() {
83 4 : static ClassMapData instance;
84 4 : return &instance;
85 : }
86 : };
87 :
88 : template < typename T >
89 0 : bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local )
90 : {
91 0 : _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) );
92 :
93 0 : if ( !_inout_local.is() )
94 : {
95 0 : if ( _inout_local.env().ExceptionCheck())
96 : {
97 0 : return false;
98 : }
99 0 : else if ( _weak != NULL )
100 : {
101 0 : _inout_local.env().DeleteWeakGlobalRef( _weak );
102 0 : _weak = NULL;
103 : }
104 : }
105 0 : return true;
106 : }
107 :
108 : // Load a class. A map from pairs of (classPath, name) to pairs of weak Java
109 : // references to (ClassLoader, Class) is maintained, so that a class is only
110 : // loaded once.
111 : //
112 : // It may happen that the weak reference to the ClassLoader becomes null while
113 : // the reference to the Class remains non-null (in case the Class was actually
114 : // loaded by some parent of the ClassLoader), in which case the ClassLoader is
115 : // resurrected (which cannot cause any classes to be loaded multiple times, as
116 : // the ClassLoader is no longer reachable, so no classes it has ever loaded are
117 : // still reachable).
118 : //
119 : // Similarly, it may happen that the weak reference to the Class becomes null
120 : // while the reference to the ClassLoader remains non-null, in which case the
121 : // Class is simply re-loaded.
122 : //
123 : // This code is close to the implementation of jvmaccess::ClassPath::loadClass
124 : // in jvmaccess/classpath.hxx, but not close enough to avoid the duplication.
125 : //
126 : // If false is returned, a (still pending) JNI exception occurred.
127 4 : bool loadClass(
128 : Reference< XComponentContext > const & context, JNIEnv& environment,
129 : OUString const & classPath, OUString const & name,
130 : LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr)
131 : {
132 : OSL_ASSERT(classLoaderPtr != NULL);
133 : // For any jweak entries still present in the map upon destruction,
134 : // DeleteWeakGlobalRef is not called (which is a leak):
135 : ClassMapData * d =
136 : rtl_Instance< ClassMapData, ClassMapDataInit, osl::MutexGuard,
137 : osl::GetGlobalMutex >::create(
138 4 : ClassMapDataInit(), osl::GetGlobalMutex());
139 4 : osl::MutexGuard g(d->mutex);
140 4 : ClassMap::iterator i(d->map.begin());
141 8 : LocalRef< jobject > cloader(environment);
142 8 : LocalRef< jclass > cl(environment);
143 : // Prune dangling weak references from the list while searching for a match,
144 : // so that the list cannot grow unbounded:
145 4 : for (; i != d->map.end();)
146 : {
147 0 : LocalRef< jobject > classLoader( environment );
148 0 : if ( !getLocalFromWeakRef( i->classLoader, classLoader ) )
149 0 : return false;
150 :
151 0 : LocalRef< jclass > classObject( environment );
152 0 : if ( !getLocalFromWeakRef( i->classObject, classObject ) )
153 0 : return false;
154 :
155 0 : if ( !classLoader.is() && !classObject.is() )
156 : {
157 0 : i = d->map.erase(i);
158 : }
159 0 : else if ( i->classPath == classPath && i->className == name )
160 : {
161 0 : cloader.set( classLoader.release() );
162 0 : cl.set( classObject.release() );
163 0 : break;
164 : }
165 : else
166 : {
167 0 : ++i;
168 : }
169 0 : }
170 4 : if ( !cloader.is() || !cl.is() )
171 : {
172 4 : if ( i == d->map.end() )
173 : {
174 : // Push a new ClassMapEntry (which can potentially fail) before
175 : // loading the class, so that it never happens that a class is
176 : // loaded but not added to the map (which could have effects on the
177 : // JVM that are not easily undone). If the pushed ClassMapEntry is
178 : // not used after all (return false, etc.) it will be pruned on next
179 : // call because its classLoader/classObject are null:
180 4 : d->map.push_front( ClassMapEntry( classPath, name ) );
181 4 : i = d->map.begin();
182 : }
183 :
184 4 : LocalRef< jclass > clClass( environment );
185 4 : clClass.set( environment.FindClass( "java/net/URLClassLoader" ) );
186 4 : if ( !clClass.is() )
187 0 : return false;
188 :
189 4 : jweak wcloader = NULL;
190 4 : if (!cloader.is())
191 : {
192 4 : jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) );
193 4 : if (ctorLoader == NULL)
194 0 : return false;
195 :
196 4 : LocalRef< jobjectArray > arr( environment );
197 4 : arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) );
198 4 : if ( !arr.is() )
199 0 : return false;
200 :
201 : jvalue arg;
202 4 : arg.l = arr.get();
203 4 : cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) );
204 4 : if ( !cloader.is() )
205 0 : return false;
206 :
207 4 : wcloader = environment.NewWeakGlobalRef( cloader.get() );
208 4 : if ( wcloader == NULL )
209 0 : return false;
210 : }
211 :
212 4 : jweak wcl = NULL;
213 4 : if ( !cl.is() )
214 : {
215 4 : jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) );
216 4 : if ( methLoadClass == NULL )
217 0 : return false;
218 :
219 4 : LocalRef< jstring > str( environment );
220 4 : str.set( convertwchar_tToJavaString( &environment, name ) );
221 4 : if ( !str.is() )
222 0 : return false;
223 :
224 : jvalue arg;
225 4 : arg.l = str.get();
226 4 : cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) );
227 4 : if ( !cl.is() )
228 0 : return false;
229 :
230 4 : wcl = environment.NewWeakGlobalRef( cl.get() );
231 4 : if ( wcl == NULL )
232 0 : return false;
233 : }
234 :
235 4 : if ( wcloader != NULL)
236 : {
237 4 : i->classLoader = wcloader;
238 : }
239 4 : if ( wcl != NULL )
240 : {
241 4 : i->classObject = wcl;
242 4 : }
243 : }
244 :
245 4 : classLoaderPtr->set( cloader.release() );
246 4 : classPtr->set( cl.release() );
247 8 : return true;
248 : }
249 :
250 : }
251 :
252 :
253 0 : IMPLEMENT_SERVICE_INFO(java_sql_Connection,"com.sun.star.sdbcx.JConnection","com.sun.star.sdbc.Connection");
254 :
255 :
256 : //************ Class: java.sql.Connection
257 :
258 : jclass java_sql_Connection::theClass = 0;
259 :
260 4 : java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver )
261 : :java_lang_Object()
262 : ,OSubComponent<java_sql_Connection, java_sql_Connection_BASE>((::cppu::OWeakObject*)(&_rDriver), this)
263 4 : ,m_xContext( _rDriver.getContext() )
264 : ,m_pDriver( &_rDriver )
265 : ,m_pDriverobject(NULL)
266 : ,m_pDriverClassLoader()
267 : ,m_Driver_theClass(NULL)
268 4 : ,m_aLogger( _rDriver.getLogger() )
269 : ,m_bParameterSubstitution(false)
270 : ,m_bIgnoreDriverPrivileges(true)
271 12 : ,m_bIgnoreCurrency(false)
272 : {
273 4 : }
274 :
275 6 : java_sql_Connection::~java_sql_Connection()
276 : {
277 2 : ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM();
278 2 : if ( xTest.is() )
279 : {
280 2 : SDBThreadAttach t;
281 2 : clearObject(*t.pEnv);
282 :
283 : {
284 2 : if ( m_pDriverobject )
285 2 : t.pEnv->DeleteGlobalRef( m_pDriverobject );
286 2 : m_pDriverobject = NULL;
287 2 : if ( m_Driver_theClass )
288 2 : t.pEnv->DeleteGlobalRef( m_Driver_theClass );
289 2 : m_Driver_theClass = NULL;
290 : }
291 2 : SDBThreadAttach::releaseRef();
292 2 : }
293 4 : }
294 :
295 160 : void SAL_CALL java_sql_Connection::release() throw()
296 : {
297 160 : relase_ChildImpl();
298 160 : }
299 :
300 2 : void java_sql_Connection::disposing()
301 : {
302 2 : ::osl::MutexGuard aGuard(m_aMutex);
303 :
304 2 : m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION );
305 :
306 2 : dispose_ChildImpl();
307 2 : java_sql_Connection_BASE::disposing();
308 :
309 2 : if ( object )
310 : {
311 : static jmethodID mID(NULL);
312 2 : callVoidMethod_ThrowSQL("close", mID);
313 2 : }
314 2 : }
315 :
316 10 : jclass java_sql_Connection::getMyClass() const
317 : {
318 : // the class must be fetched only once, therefore static
319 10 : if( !theClass )
320 4 : theClass = findMyClass("java/sql/Connection");
321 10 : return theClass;
322 : }
323 :
324 :
325 0 : OUString SAL_CALL java_sql_Connection::getCatalog( ) throw(SQLException, RuntimeException, std::exception)
326 : {
327 0 : ::osl::MutexGuard aGuard( m_aMutex );
328 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
329 :
330 : static jmethodID mID(NULL);
331 0 : return callStringMethod("getCatalog",mID);
332 : }
333 :
334 72 : Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( ) throw(SQLException, RuntimeException, std::exception)
335 : {
336 72 : ::osl::MutexGuard aGuard( m_aMutex );
337 72 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
338 :
339 :
340 72 : Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
341 72 : if(!xMetaData.is())
342 : {
343 4 : SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
344 : static jmethodID mID(NULL);
345 4 : jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID);
346 4 : if(out)
347 : {
348 4 : xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this );
349 4 : m_xMetaData = xMetaData;
350 4 : }
351 : }
352 :
353 72 : return xMetaData;
354 : }
355 :
356 2 : void SAL_CALL java_sql_Connection::close( ) throw(SQLException, RuntimeException, std::exception)
357 : {
358 2 : dispose();
359 2 : }
360 :
361 0 : void SAL_CALL java_sql_Connection::commit( ) throw(SQLException, RuntimeException, std::exception)
362 : {
363 : static jmethodID mID(NULL);
364 0 : callVoidMethod_ThrowSQL("commit", mID);
365 0 : }
366 :
367 0 : sal_Bool SAL_CALL java_sql_Connection::isClosed( ) throw(SQLException, RuntimeException, std::exception)
368 : {
369 0 : ::osl::MutexGuard aGuard( m_aMutex );
370 :
371 : static jmethodID mID(NULL);
372 0 : return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed;
373 : }
374 :
375 0 : sal_Bool SAL_CALL java_sql_Connection::isReadOnly( ) throw(SQLException, RuntimeException, std::exception)
376 : {
377 0 : ::osl::MutexGuard aGuard( m_aMutex );
378 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
379 : static jmethodID mID(NULL);
380 0 : return callBooleanMethod( "isReadOnly", mID );
381 : }
382 :
383 0 : void SAL_CALL java_sql_Connection::setCatalog( const OUString& catalog ) throw(SQLException, RuntimeException, std::exception)
384 : {
385 : static jmethodID mID(NULL);
386 0 : callVoidMethodWithStringArg("setCatalog",mID,catalog);
387 0 : }
388 :
389 0 : void SAL_CALL java_sql_Connection::rollback( ) throw(SQLException, RuntimeException, std::exception)
390 : {
391 : static jmethodID mID(NULL);
392 0 : callVoidMethod_ThrowSQL("rollback", mID);
393 0 : }
394 :
395 0 : sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( ) throw(SQLException, RuntimeException, std::exception)
396 : {
397 : static jmethodID mID(NULL);
398 0 : return callBooleanMethod( "getAutoCommit", mID );
399 : }
400 :
401 0 : void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly ) throw(SQLException, RuntimeException, std::exception)
402 : {
403 : static jmethodID mID(NULL);
404 0 : callVoidMethodWithBoolArg_ThrowSQL("setReadOnly", mID, readOnly);
405 0 : }
406 :
407 0 : void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException, std::exception)
408 : {
409 : static jmethodID mID(NULL);
410 0 : callVoidMethodWithBoolArg_ThrowSQL("setAutoCommit", mID, autoCommit);
411 0 : }
412 :
413 0 : Reference< ::com::sun::star::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( ) throw(SQLException, RuntimeException, std::exception)
414 : {
415 0 : ::osl::MutexGuard aGuard( m_aMutex );
416 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
417 :
418 0 : SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
419 : static jmethodID mID(NULL);
420 0 : callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID);
421 : // WARNING: the caller becomes the owner of the returned pointer
422 0 : return 0;
423 : }
424 :
425 0 : void SAL_CALL java_sql_Connection::setTypeMap( const Reference< ::com::sun::star::container::XNameAccess >& /*typeMap*/ ) throw(SQLException, RuntimeException, std::exception)
426 : {
427 0 : ::osl::MutexGuard aGuard( m_aMutex );
428 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
429 :
430 0 : ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
431 0 : }
432 :
433 :
434 0 : sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( ) throw(SQLException, RuntimeException, std::exception)
435 : {
436 0 : ::osl::MutexGuard aGuard( m_aMutex );
437 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
438 :
439 : static jmethodID mID(NULL);
440 0 : return callIntMethod_ThrowSQL("getTransactionIsolation", mID);
441 : }
442 :
443 0 : void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException, std::exception)
444 : {
445 0 : ::osl::MutexGuard aGuard( m_aMutex );
446 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
447 :
448 : static jmethodID mID(NULL);
449 0 : callVoidMethodWithIntArg_ThrowSQL("setTransactionIsolation", mID, level);
450 0 : }
451 :
452 6 : Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( ) throw(SQLException, RuntimeException, std::exception)
453 : {
454 6 : ::osl::MutexGuard aGuard( m_aMutex );
455 6 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
456 6 : m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT );
457 :
458 12 : SDBThreadAttach t;
459 6 : java_sql_Statement* pStatement = new java_sql_Statement( t.pEnv, *this );
460 6 : Reference< XStatement > xStmt = pStatement;
461 6 : m_aStatements.push_back( WeakReferenceHelper( xStmt ) );
462 :
463 6 : m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() );
464 12 : return xStmt;
465 : }
466 :
467 0 : OUString java_sql_Connection::transFormPreparedStatement(const OUString& _sSQL)
468 : {
469 0 : OUString sSqlStatement = _sSQL;
470 0 : if ( m_bParameterSubstitution )
471 : {
472 : try
473 : {
474 0 : OSQLParser aParser( m_pDriver->getContext() );
475 0 : OUString sErrorMessage;
476 0 : OUString sNewSql;
477 0 : OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
478 0 : if(pNode)
479 : { // special handling for parameters
480 0 : OSQLParseNode::substituteParameterNames(pNode);
481 0 : pNode->parseNodeToStr( sNewSql, this );
482 0 : delete pNode;
483 0 : sSqlStatement = sNewSql;
484 0 : }
485 : }
486 0 : catch(const Exception&)
487 : {
488 : }
489 : }
490 0 : return sSqlStatement;
491 : }
492 :
493 0 : Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql ) throw(SQLException, RuntimeException, std::exception)
494 : {
495 0 : ::osl::MutexGuard aGuard( m_aMutex );
496 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
497 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
498 :
499 0 : SDBThreadAttach t;
500 0 : OUString sSqlStatement = sql;
501 0 : sSqlStatement = transFormPreparedStatement( sSqlStatement );
502 :
503 0 : java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sSqlStatement );
504 0 : Reference< XPreparedStatement > xReturn( pStatement );
505 0 : m_aStatements.push_back(WeakReferenceHelper(xReturn));
506 :
507 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() );
508 0 : return xReturn;
509 : }
510 :
511 0 : Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const OUString& sql ) throw(SQLException, RuntimeException, std::exception)
512 : {
513 0 : ::osl::MutexGuard aGuard( m_aMutex );
514 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
515 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql );
516 :
517 0 : SDBThreadAttach t;
518 0 : OUString sSqlStatement = sql;
519 0 : sSqlStatement = transFormPreparedStatement( sSqlStatement );
520 :
521 0 : java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sSqlStatement );
522 0 : Reference< XPreparedStatement > xStmt( pStatement );
523 0 : m_aStatements.push_back(WeakReferenceHelper(xStmt));
524 :
525 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() );
526 0 : return xStmt;
527 : }
528 :
529 0 : OUString SAL_CALL java_sql_Connection::nativeSQL( const OUString& sql ) throw(SQLException, RuntimeException, std::exception)
530 : {
531 0 : ::osl::MutexGuard aGuard( m_aMutex );
532 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
533 :
534 0 : OUString aStr;
535 0 : SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
536 : {
537 :
538 : // initialize temporary Variable
539 : static const char * cSignature = "(Ljava/lang/String;)Ljava/lang/String;";
540 : static const char * cMethodName = "nativeSQL";
541 : // Java-Call
542 : static jmethodID mID(NULL);
543 0 : obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID);
544 : // Convert Parameter
545 0 : jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql));
546 :
547 0 : jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() );
548 0 : aStr = JavaString2String(t.pEnv, static_cast<jstring>(out) );
549 0 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
550 : } //t.pEnv
551 :
552 0 : m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr );
553 :
554 0 : return aStr;
555 : }
556 :
557 0 : void SAL_CALL java_sql_Connection::clearWarnings( ) throw(SQLException, RuntimeException, std::exception)
558 : {
559 : static jmethodID mID(NULL);
560 0 : callVoidMethod_ThrowSQL("clearWarnings", mID);
561 0 : }
562 :
563 0 : Any SAL_CALL java_sql_Connection::getWarnings( ) throw(SQLException, RuntimeException, std::exception)
564 : {
565 0 : ::osl::MutexGuard aGuard( m_aMutex );
566 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
567 :
568 0 : SDBThreadAttach t;
569 : static jmethodID mID(NULL);
570 0 : jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
571 : // WARNING: the caller becomes the owner of the returned pointer
572 0 : if( out )
573 : {
574 0 : java_sql_SQLWarning_BASE warn_base(t.pEnv, out);
575 0 : SQLException aAsException( static_cast< css::sdbc::SQLException >( java_sql_SQLWarning( warn_base, *this ) ) );
576 :
577 : // translate to warning
578 0 : SQLWarning aWarning;
579 0 : aWarning.Context = aAsException.Context;
580 0 : aWarning.Message = aAsException.Message;
581 0 : aWarning.SQLState = aAsException.SQLState;
582 0 : aWarning.ErrorCode = aAsException.ErrorCode;
583 0 : aWarning.NextException = aAsException.NextException;
584 :
585 0 : return makeAny( aWarning );
586 : }
587 :
588 0 : return Any();
589 : }
590 :
591 :
592 : namespace
593 : {
594 0 : OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const OUString& _rDriverClass, const OUString& _rDriverClassPath )
595 : {
596 : OUString sError1( _aResource.getResourceStringWithSubstitution(
597 : STR_NO_CLASSNAME,
598 : "$classname$", _rDriverClass
599 0 : ) );
600 0 : if ( !_rDriverClassPath.isEmpty() )
601 : {
602 : const OUString sError2( _aResource.getResourceStringWithSubstitution(
603 : STR_NO_CLASSNAME_PATH,
604 : "$classpath$", _rDriverClassPath
605 0 : ) );
606 0 : sError1 += sError2;
607 : } // if ( _rDriverClassPath.getLength() )
608 0 : return sError1;
609 : }
610 : }
611 :
612 :
613 : namespace
614 : {
615 4 : bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger,
616 : JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties )
617 : {
618 4 : if ( _rSystemProperties.getLength() == 0 )
619 : // nothing to do
620 0 : return true;
621 :
622 4 : LocalRef< jclass > systemClass( _rEnv );
623 4 : jmethodID nSetPropertyMethodID = 0;
624 : // retrieve the java.lang.System class
625 4 : systemClass.set( _rEnv.FindClass( "java/lang/System" ) );
626 4 : if ( systemClass.is() )
627 : {
628 : nSetPropertyMethodID = _rEnv.GetStaticMethodID(
629 4 : systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
630 : }
631 :
632 4 : if ( nSetPropertyMethodID == 0 )
633 0 : return false;
634 :
635 16 : for ( const NamedValue* pSystemProp = _rSystemProperties.getConstArray();
636 8 : pSystemProp != _rSystemProperties.getConstArray() + _rSystemProperties.getLength();
637 : ++pSystemProp
638 : )
639 : {
640 4 : OUString sValue;
641 4 : OSL_VERIFY( pSystemProp->Value >>= sValue );
642 :
643 4 : _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, pSystemProp->Name, sValue );
644 :
645 8 : LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, pSystemProp->Name ) );
646 8 : LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) );
647 :
648 4 : _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() );
649 8 : LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() );
650 4 : if ( throwable.is() )
651 0 : return false;
652 4 : }
653 :
654 4 : return true;
655 : }
656 : }
657 :
658 :
659 4 : void java_sql_Connection::loadDriverFromProperties( const OUString& _sDriverClass, const OUString& _sDriverClassPath,
660 : const Sequence< NamedValue >& _rSystemProperties )
661 : {
662 : // contains the statement which should be used when query for automatically generated values
663 4 : OUString sGeneratedValueStatement;
664 : // set to <TRUE/> when we should allow to query for generated values
665 4 : bool bAutoRetrievingEnabled = false;
666 :
667 : // first try if the jdbc driver is already registered at the driver manager
668 8 : SDBThreadAttach t;
669 : try
670 : {
671 4 : if ( !object )
672 : {
673 4 : if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) )
674 0 : ThrowLoggedSQLException( getLogger(), t.pEnv, *this );
675 :
676 4 : m_pDriverClassLoader.reset();
677 :
678 : // here I try to find the class for jdbc driver
679 4 : java_sql_SQLException_BASE::st_getMyClass();
680 4 : java_lang_Throwable::st_getMyClass();
681 :
682 4 : if ( _sDriverClass.isEmpty() )
683 : {
684 0 : m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS );
685 : ::dbtools::throwGenericSQLException(
686 0 : lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
687 : *this
688 0 : );
689 : }
690 : else
691 : {
692 4 : m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass );
693 : // the driver manager holds the class of the driver for later use
694 4 : boost::scoped_ptr< java_lang_Class > pDrvClass;
695 4 : if ( _sDriverClassPath.isEmpty() )
696 : {
697 : // if forName didn't find the class it will throw an exception
698 0 : pDrvClass.reset(java_lang_Class::forName(_sDriverClass));
699 : }
700 : else
701 : {
702 4 : LocalRef< jclass > driverClass(t.env());
703 8 : LocalRef< jobject > driverClassLoader(t.env());
704 :
705 : loadClass(
706 4 : m_pDriver->getContext(),
707 8 : t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass );
708 :
709 4 : m_pDriverClassLoader.set( driverClassLoader );
710 4 : pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) );
711 :
712 8 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
713 : }
714 4 : if ( pDrvClass.get() )
715 : {
716 4 : LocalRef< jobject > driverObject( t.env() );
717 4 : driverObject.set( pDrvClass->newInstanceObject() );
718 4 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
719 4 : m_pDriverobject = driverObject.release();
720 :
721 4 : if( m_pDriverobject )
722 4 : m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject );
723 :
724 : {
725 4 : jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject);
726 4 : if ( m_pDriverobject )
727 : {
728 4 : m_Driver_theClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass ));
729 4 : t.pEnv->DeleteLocalRef( tempClass );
730 : }
731 4 : }
732 : }
733 4 : m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS );
734 : }
735 : }
736 : }
737 0 : catch( const SQLException& e )
738 : {
739 : throw SQLException(
740 0 : lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
741 : *this,
742 : OUString(),
743 : 1000,
744 : makeAny(e)
745 0 : );
746 : }
747 0 : catch( Exception& )
748 : {
749 : ::dbtools::throwGenericSQLException(
750 0 : lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
751 : *this
752 0 : );
753 : }
754 :
755 4 : enableAutoRetrievingEnabled( bAutoRetrievingEnabled );
756 8 : setAutoRetrievingStatement( sGeneratedValueStatement );
757 4 : }
758 :
759 0 : OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass)
760 : {
761 0 : static const OUString s_sNodeName("org.openoffice.Office.DataAccess/JDBC/DriverClassPaths");
762 : ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext(
763 0 : m_pDriver->getContext(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
764 0 : OUString sURL;
765 0 : if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) )
766 : {
767 0 : ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass );
768 0 : OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL );
769 : }
770 0 : return sURL;
771 : }
772 :
773 4 : bool java_sql_Connection::construct(const OUString& url,
774 : const Sequence< PropertyValue >& info)
775 : {
776 : { // initialize the java vm
777 4 : ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(m_xContext);
778 4 : if ( !xTest.is() )
779 0 : throwGenericSQLException(STR_NO_JAVA,*this);
780 : }
781 4 : SDBThreadAttach t;
782 4 : SDBThreadAttach::addRef(); // will be released in dtor
783 4 : if ( !t.pEnv )
784 0 : throwGenericSQLException(STR_NO_JAVA,*this);
785 :
786 8 : OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
787 4 : bool bAutoRetrievingEnabled = false; // set to <TRUE/> when we should allow to query for generated values
788 8 : OUString sDriverClassPath,sDriverClass;
789 8 : Sequence< NamedValue > aSystemProperties;
790 :
791 8 : ::comphelper::NamedValueCollection aSettings( info );
792 4 : sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass );
793 4 : sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath);
794 4 : if ( sDriverClassPath.isEmpty() )
795 0 : sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
796 4 : bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
797 4 : sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
798 4 : m_bParameterSubstitution = aSettings.getOrDefault( "ParameterNameSubstitution", m_bParameterSubstitution );
799 4 : m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
800 4 : m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
801 4 : aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
802 4 : m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() );
803 4 : m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() );
804 :
805 4 : loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties );
806 :
807 4 : enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
808 4 : setAutoRetrievingStatement(sGeneratedValueStatement);
809 :
810 4 : if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
811 : {
812 : // initialize temporary Variable
813 : static const char * cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;";
814 : static const char * cMethodName = "connect";
815 : // Java-Call
816 4 : jmethodID mID = NULL;
817 4 : if ( !mID )
818 4 : mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature );
819 4 : if ( mID )
820 : {
821 : jvalue args[2];
822 : // convert Parameter
823 4 : args[0].l = convertwchar_tToJavaString(t.pEnv,url);
824 4 : java_util_Properties* pProps = createStringPropertyArray(info);
825 4 : args[1].l = pProps->getJavaObject();
826 :
827 4 : LocalRef< jobject > ensureDelete( t.env(), args[0].l );
828 :
829 4 : jobject out = NULL;
830 : // In some cases (e.g.,
831 : // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
832 : // l. 249) the JavaDriverClassPath contains multiple jars,
833 : // as creating the JavaDriverClass instance requires
834 : // (reflective) access to those other jars. Now, if the
835 : // JavaDriverClass is actually loaded by some parent class
836 : // loader (e.g., because its jar is also on the global
837 : // class path), it would still not have access to the
838 : // additional jars on the JavaDriverClassPath. Hence, the
839 : // JavaDriverClassPath class loader is pushed as context
840 : // class loader around the JavaDriverClass instance
841 : // creation:
842 : // #i82222# / 2007-10-15
843 : {
844 4 : ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this );
845 4 : out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l );
846 4 : delete pProps, pProps = NULL;
847 4 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
848 : }
849 :
850 4 : if ( !out )
851 0 : m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION );
852 :
853 4 : if ( out )
854 4 : object = t.pEnv->NewGlobalRef( out );
855 :
856 4 : if ( object )
857 4 : m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url );
858 :
859 4 : m_aConnectionInfo = info;
860 : } //mID
861 : } //t.pEnv
862 8 : return object != NULL;
863 : }
864 :
865 :
866 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|