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