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 10 : bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local )
90 : {
91 10 : _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) );
92 :
93 10 : 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 10 : 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 9 : 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 9 : ClassMapDataInit(), osl::GetGlobalMutex());
139 9 : osl::MutexGuard g(d->mutex);
140 9 : ClassMap::iterator i(d->map.begin());
141 18 : LocalRef< jobject > cloader(environment);
142 18 : 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 9 : for (; i != d->map.end();)
146 : {
147 5 : LocalRef< jobject > classLoader( environment );
148 5 : if ( !getLocalFromWeakRef( i->classLoader, classLoader ) )
149 0 : return false;
150 :
151 5 : LocalRef< jclass > classObject( environment );
152 5 : if ( !getLocalFromWeakRef( i->classObject, classObject ) )
153 0 : return false;
154 :
155 5 : if ( !classLoader.is() && !classObject.is() )
156 : {
157 0 : i = d->map.erase(i);
158 : }
159 5 : else if ( i->classPath == classPath && i->className == name )
160 : {
161 5 : cloader.set( classLoader.release() );
162 5 : cl.set( classObject.release() );
163 5 : break;
164 : }
165 : else
166 : {
167 0 : ++i;
168 : }
169 0 : }
170 9 : 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 9 : classLoaderPtr->set( cloader.release() );
246 9 : classPtr->set( cl.release() );
247 18 : 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 9 : java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver )
261 : :java_lang_Object()
262 : ,OSubComponent<java_sql_Connection, java_sql_Connection_BASE>(static_cast<cppu::OWeakObject*>(const_cast<java_sql_Driver *>(&_rDriver)), this)
263 9 : ,m_xContext( _rDriver.getContext() )
264 : ,m_pDriver( &_rDriver )
265 : ,m_pDriverobject(NULL)
266 : ,m_pDriverClassLoader()
267 : ,m_Driver_theClass(NULL)
268 9 : ,m_aLogger( _rDriver.getLogger() )
269 : ,m_bParameterSubstitution(false)
270 : ,m_bIgnoreDriverPrivileges(true)
271 27 : ,m_bIgnoreCurrency(false)
272 : {
273 9 : }
274 :
275 27 : java_sql_Connection::~java_sql_Connection()
276 : {
277 9 : ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM();
278 9 : if ( xTest.is() )
279 : {
280 9 : SDBThreadAttach t;
281 9 : clearObject(*t.pEnv);
282 :
283 : {
284 9 : if ( m_pDriverobject )
285 9 : t.pEnv->DeleteGlobalRef( m_pDriverobject );
286 9 : m_pDriverobject = NULL;
287 9 : if ( m_Driver_theClass )
288 9 : t.pEnv->DeleteGlobalRef( m_Driver_theClass );
289 9 : m_Driver_theClass = NULL;
290 : }
291 9 : SDBThreadAttach::releaseRef();
292 9 : }
293 18 : }
294 :
295 1328 : void SAL_CALL java_sql_Connection::release() throw()
296 : {
297 1328 : relase_ChildImpl();
298 1328 : }
299 :
300 9 : void java_sql_Connection::disposing()
301 : {
302 9 : ::osl::MutexGuard aGuard(m_aMutex);
303 :
304 9 : m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION );
305 :
306 9 : dispose_ChildImpl();
307 9 : java_sql_Connection_BASE::disposing();
308 :
309 9 : if ( object )
310 : {
311 : static jmethodID mID(NULL);
312 9 : callVoidMethod_ThrowSQL("close", mID);
313 9 : }
314 9 : }
315 :
316 17 : jclass java_sql_Connection::getMyClass() const
317 : {
318 : // the class must be fetched only once, therefore static
319 17 : if( !theClass )
320 4 : theClass = findMyClass("java/sql/Connection");
321 17 : 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 1955 : Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( ) throw(SQLException, RuntimeException, std::exception)
335 : {
336 1955 : ::osl::MutexGuard aGuard( m_aMutex );
337 1955 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
338 :
339 :
340 1955 : Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
341 1955 : if(!xMetaData.is())
342 : {
343 9 : SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
344 : static jmethodID mID(NULL);
345 9 : jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID);
346 9 : if(out)
347 : {
348 9 : xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this );
349 9 : m_xMetaData = xMetaData;
350 9 : }
351 : }
352 :
353 1955 : return xMetaData;
354 : }
355 :
356 9 : void SAL_CALL java_sql_Connection::close( ) throw(SQLException, RuntimeException, std::exception)
357 : {
358 9 : dispose();
359 9 : }
360 :
361 6 : void SAL_CALL java_sql_Connection::commit( ) throw(SQLException, RuntimeException, std::exception)
362 : {
363 : static jmethodID mID(NULL);
364 6 : callVoidMethod_ThrowSQL("commit", mID);
365 6 : }
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 6 : sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( ) throw(SQLException, RuntimeException, std::exception)
396 : {
397 : static jmethodID mID(NULL);
398 6 : 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 12 : void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException, std::exception)
408 : {
409 : static jmethodID mID(NULL);
410 12 : callVoidMethodWithBoolArg_ThrowSQL("setAutoCommit", mID, autoCommit);
411 12 : }
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 212 : Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( ) throw(SQLException, RuntimeException, std::exception)
453 : {
454 212 : ::osl::MutexGuard aGuard( m_aMutex );
455 212 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
456 212 : m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT );
457 :
458 424 : SDBThreadAttach t;
459 212 : java_sql_Statement* pStatement = new java_sql_Statement( t.pEnv, *this );
460 212 : Reference< XStatement > xStmt = pStatement;
461 212 : m_aStatements.push_back( WeakReferenceHelper( xStmt ) );
462 :
463 212 : m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() );
464 424 : return xStmt;
465 : }
466 :
467 55 : OUString java_sql_Connection::transFormPreparedStatement(const OUString& _sSQL)
468 : {
469 55 : OUString sSqlStatement = _sSQL;
470 55 : 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 55 : return sSqlStatement;
491 : }
492 :
493 55 : Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql ) throw(SQLException, RuntimeException, std::exception)
494 : {
495 55 : ::osl::MutexGuard aGuard( m_aMutex );
496 55 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
497 55 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
498 :
499 110 : SDBThreadAttach t;
500 110 : OUString sSqlStatement = sql;
501 55 : sSqlStatement = transFormPreparedStatement( sSqlStatement );
502 :
503 55 : java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sSqlStatement );
504 55 : Reference< XPreparedStatement > xReturn( pStatement );
505 55 : m_aStatements.push_back(WeakReferenceHelper(xReturn));
506 :
507 55 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() );
508 110 : 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 9 : bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger,
616 : JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties )
617 : {
618 9 : if ( _rSystemProperties.getLength() == 0 )
619 : // nothing to do
620 0 : return true;
621 :
622 9 : LocalRef< jclass > systemClass( _rEnv );
623 9 : jmethodID nSetPropertyMethodID = 0;
624 : // retrieve the java.lang.System class
625 9 : systemClass.set( _rEnv.FindClass( "java/lang/System" ) );
626 9 : if ( systemClass.is() )
627 : {
628 : nSetPropertyMethodID = _rEnv.GetStaticMethodID(
629 9 : systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
630 : }
631 :
632 9 : if ( nSetPropertyMethodID == 0 )
633 0 : return false;
634 :
635 36 : for ( const NamedValue* pSystemProp = _rSystemProperties.getConstArray();
636 18 : pSystemProp != _rSystemProperties.getConstArray() + _rSystemProperties.getLength();
637 : ++pSystemProp
638 : )
639 : {
640 9 : OUString sValue;
641 9 : OSL_VERIFY( pSystemProp->Value >>= sValue );
642 :
643 9 : _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, pSystemProp->Name, sValue );
644 :
645 18 : LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, pSystemProp->Name ) );
646 18 : LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) );
647 :
648 9 : _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() );
649 18 : LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() );
650 9 : if ( throwable.is() )
651 0 : return false;
652 9 : }
653 :
654 9 : return true;
655 : }
656 : }
657 :
658 :
659 9 : 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 9 : OUString sGeneratedValueStatement;
664 : // set to <TRUE/> when we should allow to query for generated values
665 9 : bool bAutoRetrievingEnabled = false;
666 :
667 : // first try if the jdbc driver is already registered at the driver manager
668 18 : SDBThreadAttach t;
669 : try
670 : {
671 9 : if ( !object )
672 : {
673 9 : if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) )
674 0 : ThrowLoggedSQLException( getLogger(), t.pEnv, *this );
675 :
676 9 : m_pDriverClassLoader.reset();
677 :
678 : // here I try to find the class for jdbc driver
679 9 : java_sql_SQLException_BASE::st_getMyClass();
680 9 : java_lang_Throwable::st_getMyClass();
681 :
682 9 : 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 9 : m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass );
693 : // the driver manager holds the class of the driver for later use
694 9 : boost::scoped_ptr< java_lang_Class > pDrvClass;
695 9 : 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 9 : LocalRef< jclass > driverClass(t.env());
703 18 : LocalRef< jobject > driverClassLoader(t.env());
704 :
705 : loadClass(
706 9 : m_pDriver->getContext(),
707 18 : t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass );
708 :
709 9 : m_pDriverClassLoader.set( driverClassLoader );
710 9 : pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) );
711 :
712 18 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
713 : }
714 9 : if ( pDrvClass.get() )
715 : {
716 9 : LocalRef< jobject > driverObject( t.env() );
717 9 : driverObject.set( pDrvClass->newInstanceObject() );
718 9 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
719 9 : m_pDriverobject = driverObject.release();
720 :
721 9 : if( m_pDriverobject )
722 9 : m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject );
723 :
724 : {
725 9 : jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject);
726 9 : if ( m_pDriverobject )
727 : {
728 9 : m_Driver_theClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass ));
729 9 : t.pEnv->DeleteLocalRef( tempClass );
730 : }
731 9 : }
732 : }
733 9 : 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 9 : enableAutoRetrievingEnabled( bAutoRetrievingEnabled );
756 18 : setAutoRetrievingStatement( sGeneratedValueStatement );
757 9 : }
758 :
759 0 : OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass)
760 : {
761 : static const char 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 9 : bool java_sql_Connection::construct(const OUString& url,
774 : const Sequence< PropertyValue >& info)
775 : {
776 : { // initialize the java vm
777 9 : ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(m_xContext);
778 9 : if ( !xTest.is() )
779 0 : throwGenericSQLException(STR_NO_JAVA,*this);
780 : }
781 9 : SDBThreadAttach t;
782 9 : SDBThreadAttach::addRef(); // will be released in dtor
783 9 : if ( !t.pEnv )
784 0 : throwGenericSQLException(STR_NO_JAVA,*this);
785 :
786 18 : OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
787 9 : bool bAutoRetrievingEnabled = false; // set to <TRUE/> when we should allow to query for generated values
788 18 : OUString sDriverClassPath,sDriverClass;
789 18 : Sequence< NamedValue > aSystemProperties;
790 :
791 18 : ::comphelper::NamedValueCollection aSettings( info );
792 9 : sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass );
793 9 : sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath);
794 9 : if ( sDriverClassPath.isEmpty() )
795 0 : sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
796 9 : bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
797 9 : sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
798 9 : m_bParameterSubstitution = aSettings.getOrDefault( "ParameterNameSubstitution", m_bParameterSubstitution );
799 9 : m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
800 9 : m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
801 9 : aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
802 9 : m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() );
803 9 : m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() );
804 :
805 9 : loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties );
806 :
807 9 : enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
808 9 : setAutoRetrievingStatement(sGeneratedValueStatement);
809 :
810 9 : if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
811 : {
812 : // Java-Call
813 9 : jmethodID mID = NULL;
814 9 : if ( !mID )
815 : {
816 : // initialize temporary Variable
817 : static const char * cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;";
818 : static const char * cMethodName = "connect";
819 9 : mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature );
820 : }
821 9 : if ( mID )
822 : {
823 : jvalue args[2];
824 : // convert Parameter
825 9 : args[0].l = convertwchar_tToJavaString(t.pEnv,url);
826 9 : java_util_Properties* pProps = createStringPropertyArray(info);
827 9 : args[1].l = pProps->getJavaObject();
828 :
829 9 : LocalRef< jobject > ensureDelete( t.env(), args[0].l );
830 :
831 9 : jobject out = NULL;
832 : // In some cases (e.g.,
833 : // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
834 : // l. 249) the JavaDriverClassPath contains multiple jars,
835 : // as creating the JavaDriverClass instance requires
836 : // (reflective) access to those other jars. Now, if the
837 : // JavaDriverClass is actually loaded by some parent class
838 : // loader (e.g., because its jar is also on the global
839 : // class path), it would still not have access to the
840 : // additional jars on the JavaDriverClassPath. Hence, the
841 : // JavaDriverClassPath class loader is pushed as context
842 : // class loader around the JavaDriverClass instance
843 : // creation:
844 : // #i82222# / 2007-10-15
845 : {
846 9 : ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this );
847 9 : out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l );
848 9 : delete pProps, pProps = NULL;
849 9 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
850 : }
851 :
852 9 : if ( !out )
853 0 : m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION );
854 :
855 9 : if ( out )
856 9 : object = t.pEnv->NewGlobalRef( out );
857 :
858 9 : if ( object )
859 9 : m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url );
860 :
861 9 : m_aConnectionInfo = info;
862 : } //mID
863 : } //t.pEnv
864 18 : return object != NULL;
865 : }
866 :
867 :
868 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|