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 "datasource.hxx"
21 : #include "module_dba.hxx"
22 : #include "services.hxx"
23 : #include "userinformation.hxx"
24 : #include "commandcontainer.hxx"
25 : #include "dbastrings.hrc"
26 : #include "core_resource.hxx"
27 : #include "core_resource.hrc"
28 : #include "connection.hxx"
29 : #include "SharedConnection.hxx"
30 : #include "databasedocument.hxx"
31 : #include "OAuthenticationContinuation.hxx"
32 :
33 : #include <com/sun/star/beans/NamedValue.hpp>
34 : #include <com/sun/star/beans/PropertyAttribute.hpp>
35 : #include <com/sun/star/beans/PropertyState.hpp>
36 : #include <com/sun/star/beans/XPropertyContainer.hpp>
37 : #include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
38 : #include <com/sun/star/embed/XTransactedObject.hpp>
39 : #include <com/sun/star/lang/DisposedException.hpp>
40 : #include <com/sun/star/reflection/ProxyFactory.hpp>
41 : #include <com/sun/star/sdb/DatabaseContext.hpp>
42 : #include <com/sun/star/sdbc/ConnectionPool.hpp>
43 : #include <com/sun/star/sdbc/XDriverAccess.hpp>
44 : #include <com/sun/star/sdbc/XDriverManager.hpp>
45 : #include <com/sun/star/sdbc/DriverManager.hpp>
46 : #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
47 : #include <com/sun/star/ucb/AuthenticationRequest.hpp>
48 : #include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
49 : #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
50 : #include <com/sun/star/view/XPrintable.hpp>
51 :
52 : #include <comphelper/guarding.hxx>
53 : #include <comphelper/interaction.hxx>
54 : #include <comphelper/namedvaluecollection.hxx>
55 : #include <comphelper/property.hxx>
56 : #include <comphelper/seqstream.hxx>
57 : #include <comphelper/sequence.hxx>
58 : #include <cppuhelper/supportsservice.hxx>
59 : #include <connectivity/dbexception.hxx>
60 : #include <connectivity/dbtools.hxx>
61 : #include <cppuhelper/typeprovider.hxx>
62 : #include <tools/debug.hxx>
63 : #include <tools/diagnose_ex.h>
64 : #include <osl/diagnose.h>
65 : #include <tools/urlobj.hxx>
66 : #include <typelib/typedescription.hxx>
67 : #include <unotools/confignode.hxx>
68 : #include <unotools/sharedunocomponent.hxx>
69 : #include <rtl/digest.h>
70 :
71 : #include <algorithm>
72 : #include <iterator>
73 : #include <set>
74 :
75 : using namespace ::com::sun::star::sdbc;
76 : using namespace ::com::sun::star::sdbcx;
77 : using namespace ::com::sun::star::sdb;
78 : using namespace ::com::sun::star::beans;
79 : using namespace ::com::sun::star::uno;
80 : using namespace ::com::sun::star::lang;
81 : using namespace ::com::sun::star::embed;
82 : using namespace ::com::sun::star::container;
83 : using namespace ::com::sun::star::util;
84 : using namespace ::com::sun::star::io;
85 : using namespace ::com::sun::star::task;
86 : using namespace ::com::sun::star::ucb;
87 : using namespace ::com::sun::star::frame;
88 : using namespace ::com::sun::star::reflection;
89 : using namespace ::cppu;
90 : using namespace ::osl;
91 : using namespace ::dbtools;
92 : using namespace ::comphelper;
93 :
94 : namespace dbaccess
95 : {
96 :
97 : // FlushNotificationAdapter
98 : typedef ::cppu::WeakImplHelper1< XFlushListener > FlushNotificationAdapter_Base;
99 : /** helper class which implements a XFlushListener, and forwards all
100 : notification events to another XFlushListener
101 :
102 : The speciality is that the foreign XFlushListener instance, to which
103 : the notifications are forwarded, is held weak.
104 :
105 : Thus, the class can be used with XFlushable instance which hold
106 : their listeners with a hard reference, if you simply do not *want*
107 : to be held hard-ref-wise.
108 : */
109 : class FlushNotificationAdapter : public FlushNotificationAdapter_Base
110 : {
111 : private:
112 : WeakReference< XFlushable > m_aBroadcaster;
113 : WeakReference< XFlushListener > m_aListener;
114 :
115 : public:
116 9 : static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
117 : {
118 9 : Reference< XFlushListener > xAdapter( new FlushNotificationAdapter( _rxBroadcaster, _rxListener ) );
119 9 : }
120 :
121 : protected:
122 : FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener );
123 : virtual ~FlushNotificationAdapter();
124 :
125 : void SAL_CALL impl_dispose( bool _bRevokeListener );
126 :
127 : protected:
128 : // XFlushListener
129 : virtual void SAL_CALL flushed( const ::com::sun::star::lang::EventObject& rEvent ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
130 : // XEventListener
131 : virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
132 : };
133 :
134 9 : FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
135 : :m_aBroadcaster( _rxBroadcaster )
136 9 : ,m_aListener( _rxListener )
137 : {
138 : OSL_ENSURE( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
139 :
140 9 : osl_atomic_increment( &m_refCount );
141 : {
142 9 : if ( _rxBroadcaster.is() )
143 9 : _rxBroadcaster->addFlushListener( this );
144 : }
145 9 : osl_atomic_decrement( &m_refCount );
146 : OSL_ENSURE( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
147 9 : }
148 :
149 18 : FlushNotificationAdapter::~FlushNotificationAdapter()
150 : {
151 18 : }
152 :
153 9 : void SAL_CALL FlushNotificationAdapter::impl_dispose( bool _bRevokeListener )
154 : {
155 9 : Reference< XFlushListener > xKeepAlive( this );
156 :
157 9 : if ( _bRevokeListener )
158 : {
159 9 : Reference< XFlushable > xFlushable( m_aBroadcaster );
160 9 : if ( xFlushable.is() )
161 0 : xFlushable->removeFlushListener( this );
162 : }
163 :
164 9 : m_aListener.clear();
165 9 : m_aBroadcaster.clear();
166 9 : }
167 :
168 6 : void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent ) throw (RuntimeException, std::exception)
169 : {
170 6 : Reference< XFlushListener > xListener( m_aListener );
171 6 : if ( xListener.is() )
172 6 : xListener->flushed( rEvent );
173 : else
174 0 : impl_dispose( true );
175 6 : }
176 :
177 9 : void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source ) throw (RuntimeException, std::exception)
178 : {
179 9 : Reference< XFlushListener > xListener( m_aListener );
180 9 : if ( xListener.is() )
181 9 : xListener->disposing( Source );
182 :
183 9 : impl_dispose( true );
184 9 : }
185 :
186 0 : OAuthenticationContinuation::OAuthenticationContinuation()
187 : :m_bRemberPassword(true), // TODO: a meaningful default
188 0 : m_bCanSetUserName(true)
189 : {
190 0 : }
191 :
192 0 : sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm( ) throw(RuntimeException, std::exception)
193 : {
194 0 : return sal_False;
195 : }
196 :
197 0 : void SAL_CALL OAuthenticationContinuation::setRealm( const OUString& /*Realm*/ ) throw(RuntimeException, std::exception)
198 : {
199 : SAL_WARN("dbaccess","OAuthenticationContinuation::setRealm: not supported!");
200 0 : }
201 :
202 0 : sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName( ) throw(RuntimeException, std::exception)
203 : {
204 : // we always allow this, even if the database document is read-only. In this case,
205 : // it's simply that the user cannot store the new user name.
206 0 : return m_bCanSetUserName;
207 : }
208 :
209 0 : void SAL_CALL OAuthenticationContinuation::setUserName( const OUString& _rUser ) throw(RuntimeException, std::exception)
210 : {
211 0 : m_sUser = _rUser;
212 0 : }
213 :
214 0 : sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword( ) throw(RuntimeException, std::exception)
215 : {
216 0 : return sal_True;
217 : }
218 :
219 0 : void SAL_CALL OAuthenticationContinuation::setPassword( const OUString& _rPassword ) throw(RuntimeException, std::exception)
220 : {
221 0 : m_sPassword = _rPassword;
222 0 : }
223 :
224 0 : Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault ) throw(RuntimeException, std::exception)
225 : {
226 0 : Sequence< RememberAuthentication > aReturn(1);
227 0 : _reDefault = aReturn[0] = RememberAuthentication_SESSION;
228 0 : return aReturn;
229 : }
230 :
231 0 : void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember ) throw(RuntimeException, std::exception)
232 : {
233 0 : m_bRemberPassword = (RememberAuthentication_NO != _eRemember);
234 0 : }
235 :
236 0 : sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount( ) throw(RuntimeException, std::exception)
237 : {
238 0 : return sal_False;
239 : }
240 :
241 0 : void SAL_CALL OAuthenticationContinuation::setAccount( const OUString& ) throw(RuntimeException, std::exception)
242 : {
243 : SAL_WARN("dbaccess","OAuthenticationContinuation::setAccount: not supported!");
244 0 : }
245 :
246 0 : Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault ) throw(RuntimeException, std::exception)
247 : {
248 0 : Sequence < RememberAuthentication > aReturn(1);
249 0 : aReturn[0] = RememberAuthentication_NO;
250 0 : _reDefault = RememberAuthentication_NO;
251 0 : return aReturn;
252 : }
253 :
254 0 : void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ ) throw(RuntimeException, std::exception)
255 : {
256 : SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!");
257 0 : }
258 :
259 : /** The class OSharedConnectionManager implements a structure to share connections.
260 : It owns the master connections which will be disposed when the last connection proxy is gone.
261 : */
262 : typedef ::cppu::WeakImplHelper1< XEventListener > OConnectionHelper_BASE;
263 : // need to hold the digest
264 : struct TDigestHolder
265 : {
266 : sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
267 48 : TDigestHolder()
268 : {
269 48 : m_pBuffer[0] = 0;
270 48 : }
271 :
272 : };
273 :
274 : class OSharedConnectionManager : public OConnectionHelper_BASE
275 : {
276 :
277 : // contains the currently used master connections
278 : typedef struct
279 45 : {
280 : Reference< XConnection > xMasterConnection;
281 : oslInterlockedCount nALiveCount;
282 224 : } TConnectionHolder;
283 :
284 : // the less-compare functor, used for the stl::map
285 : struct TDigestLess : public ::std::binary_function< TDigestHolder, TDigestHolder, bool>
286 : {
287 6 : bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
288 : {
289 : sal_uInt32 i;
290 6 : for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
291 : ;
292 6 : return i < RTL_DIGEST_LENGTH_SHA1;
293 : }
294 : };
295 :
296 : typedef ::std::map< TDigestHolder,TConnectionHolder,TDigestLess> TConnectionMap; // holds the master connections
297 : typedef ::std::map< Reference< XConnection >,TConnectionMap::iterator> TSharedConnectionMap;// holds the shared connections
298 :
299 : ::osl::Mutex m_aMutex;
300 : TConnectionMap m_aConnections; // remember the master connection in conjunction with the digest
301 : TSharedConnectionMap m_aSharedConnection; // the shared connections with conjunction with an iterator into the connections map
302 : Reference< XProxyFactory > m_xProxyFactory;
303 :
304 : protected:
305 : virtual ~OSharedConnectionManager();
306 :
307 : public:
308 : OSharedConnectionManager(const Reference< XComponentContext >& _rxContext);
309 :
310 : void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
311 : Reference<XConnection> getConnection( const OUString& url,
312 : const OUString& user,
313 : const OUString& password,
314 : const Sequence< PropertyValue >& _aInfo,
315 : ODatabaseSource* _pDataSource);
316 : void addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter);
317 : };
318 :
319 40 : OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
320 : {
321 40 : m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
322 40 : }
323 :
324 78 : OSharedConnectionManager::~OSharedConnectionManager()
325 : {
326 78 : }
327 :
328 46 : void SAL_CALL OSharedConnectionManager::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException, std::exception)
329 : {
330 46 : MutexGuard aGuard(m_aMutex);
331 92 : Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
332 46 : TSharedConnectionMap::iterator aFind = m_aSharedConnection.find(xConnection);
333 46 : if ( m_aSharedConnection.end() != aFind )
334 : {
335 46 : osl_atomic_decrement(&aFind->second->second.nALiveCount);
336 46 : if ( !aFind->second->second.nALiveCount )
337 : {
338 44 : ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
339 44 : m_aConnections.erase(aFind->second);
340 : }
341 46 : m_aSharedConnection.erase(aFind);
342 46 : }
343 46 : }
344 :
345 48 : Reference<XConnection> OSharedConnectionManager::getConnection( const OUString& url,
346 : const OUString& user,
347 : const OUString& password,
348 : const Sequence< PropertyValue >& _aInfo,
349 : ODatabaseSource* _pDataSource)
350 : {
351 48 : MutexGuard aGuard(m_aMutex);
352 48 : TConnectionMap::key_type nId;
353 96 : Sequence< PropertyValue > aInfoCopy(_aInfo);
354 48 : sal_Int32 nPos = aInfoCopy.getLength();
355 48 : aInfoCopy.realloc( nPos + 2 );
356 48 : aInfoCopy[nPos].Name = "TableFilter";
357 48 : aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
358 48 : aInfoCopy[nPos].Name = "TableTypeFilter";
359 48 : aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
360 :
361 96 : OUString sUser = user;
362 96 : OUString sPassword = password;
363 48 : if ((sUser.isEmpty()) && (sPassword.isEmpty()) && (!_pDataSource->m_pImpl->m_sUser.isEmpty()))
364 : { // ease the usage of this method. data source which are intended to have a user automatically
365 : // fill in the user/password combination if the caller of this method does not specify otherwise
366 0 : sUser = _pDataSource->m_pImpl->m_sUser;
367 0 : if (!_pDataSource->m_pImpl->m_aPassword.isEmpty())
368 0 : sPassword = _pDataSource->m_pImpl->m_aPassword;
369 : }
370 :
371 48 : ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
372 48 : TConnectionMap::iterator aIter = m_aConnections.find(nId);
373 :
374 48 : if ( m_aConnections.end() == aIter )
375 : {
376 45 : TConnectionHolder aHolder;
377 45 : aHolder.nALiveCount = 0; // will be incremented by addListener
378 45 : aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
379 45 : aIter = m_aConnections.insert(TConnectionMap::value_type(nId,aHolder)).first;
380 : }
381 :
382 48 : Reference<XConnection> xRet;
383 48 : if ( aIter->second.xMasterConnection.is() )
384 : {
385 48 : Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection.get());
386 48 : xRet = new OSharedConnection(xConProxy);
387 48 : m_aSharedConnection.insert(TSharedConnectionMap::value_type(xRet,aIter));
388 48 : addEventListener(xRet,aIter);
389 : }
390 :
391 96 : return xRet;
392 : }
393 :
394 48 : void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter)
395 : {
396 48 : Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
397 48 : xComp->addEventListener(this);
398 : OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
399 48 : osl_atomic_increment(&_rIter->second.nALiveCount);
400 48 : }
401 :
402 : namespace
403 : {
404 47 : Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
405 : const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
406 : {
407 47 : if ( _xDriver.is() )
408 : {
409 47 : Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
410 :
411 47 : const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
412 47 : const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
413 :
414 56 : ::std::vector< PropertyValue > aRet;
415 :
416 2538 : for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
417 : {
418 2491 : bool bAllowSetting = false;
419 2491 : const AsciiPropertyValue* pSetting = _pKnownSettings;
420 67257 : for ( ; pSetting->AsciiName; ++pSetting )
421 : {
422 67257 : if ( pDataSourceSetting->Name.equalsAscii( pSetting->AsciiName ) )
423 : { // the particular data source setting is known
424 :
425 2491 : const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
426 2491 : const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
427 8350 : for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
428 : {
429 5955 : if ( pAllowedDriverSetting->Name.equalsAscii( pSetting->AsciiName ) )
430 : { // the driver also allows this setting
431 96 : bAllowSetting = true;
432 96 : break;
433 : }
434 : }
435 2491 : break;
436 : }
437 : }
438 2491 : if ( bAllowSetting || !pSetting->AsciiName )
439 : { // if the driver allows this particular setting, or if the setting is completely unknown,
440 : // we pass it to the driver
441 96 : aRet.push_back( *pDataSourceSetting );
442 : }
443 : }
444 47 : if ( !aRet.empty() )
445 47 : return Sequence< PropertyValue >(&(*aRet.begin()),aRet.size());
446 : }
447 9 : return Sequence< PropertyValue >();
448 : }
449 :
450 : typedef ::std::map< OUString, sal_Int32 > PropertyAttributeCache;
451 :
452 : struct IsDefaultAndNotRemoveable : public ::std::unary_function< PropertyValue, bool >
453 : {
454 : private:
455 : const PropertyAttributeCache& m_rAttribs;
456 :
457 : public:
458 104 : IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
459 :
460 5512 : bool operator()( const PropertyValue& _rProp )
461 : {
462 5512 : if ( _rProp.State != PropertyState_DEFAULT_VALUE )
463 58 : return false;
464 :
465 5454 : bool bRemoveable = true;
466 :
467 5454 : PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
468 : OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
469 5454 : if ( pos != m_rAttribs.end() )
470 5454 : bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
471 :
472 5454 : return !bRemoveable;
473 : }
474 : };
475 : }
476 :
477 : } // namespace dbaccess
478 :
479 : // ODatabaseContext
480 :
481 20 : extern "C" void SAL_CALL createRegistryInfo_ODatabaseSource()
482 : {
483 20 : static ::dba::OAutoRegistration< ::dbaccess::ODatabaseSource > aAutoRegistration;
484 20 : }
485 :
486 : namespace dbaccess
487 : {
488 :
489 256 : ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
490 : :ModelDependentComponent( _pImpl )
491 256 : ,ODatabaseSource_Base( getMutex() )
492 : ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
493 256 : ,m_aBookmarks( *this, getMutex() )
494 768 : ,m_aFlushListeners( getMutex() )
495 : {
496 : // some kind of default
497 : SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
498 256 : }
499 :
500 765 : ODatabaseSource::~ODatabaseSource()
501 : {
502 : SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
503 255 : if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
504 : {
505 0 : acquire();
506 0 : dispose();
507 : }
508 510 : }
509 :
510 88 : void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
511 : {
512 88 : ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument.get() );
513 :
514 88 : ::osl::MutexGuard aGuard( rModelImpl.m_aMutex );
515 88 : if ( rModelImpl.m_pImpl.is() )
516 88 : rModelImpl.m_pImpl->m_sName = _rNewName;
517 88 : }
518 :
519 : // com::sun::star::lang::XTypeProvider
520 6 : Sequence< Type > ODatabaseSource::getTypes() throw (RuntimeException, std::exception)
521 : {
522 6 : OTypeCollection aPropertyHelperTypes( cppu::UnoType<XFastPropertySet>::get(),
523 6 : cppu::UnoType<XPropertySet>::get(),
524 12 : cppu::UnoType<XMultiPropertySet>::get());
525 :
526 : return ::comphelper::concatSequences(
527 : ODatabaseSource_Base::getTypes(),
528 : aPropertyHelperTypes.getTypes()
529 6 : );
530 : }
531 :
532 0 : Sequence< sal_Int8 > ODatabaseSource::getImplementationId() throw (RuntimeException, std::exception)
533 : {
534 0 : return css::uno::Sequence<sal_Int8>();
535 : }
536 :
537 : // com::sun::star::uno::XInterface
538 13302 : Any ODatabaseSource::queryInterface( const Type & rType ) throw (RuntimeException, std::exception)
539 : {
540 13302 : Any aIface = ODatabaseSource_Base::queryInterface( rType );
541 13302 : if ( !aIface.hasValue() )
542 5817 : aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
543 13302 : return aIface;
544 : }
545 :
546 29803 : void ODatabaseSource::acquire() throw ()
547 : {
548 29803 : ODatabaseSource_Base::acquire();
549 29803 : }
550 :
551 29798 : void ODatabaseSource::release() throw ()
552 : {
553 29798 : ODatabaseSource_Base::release();
554 29798 : }
555 :
556 57 : void SAL_CALL ODatabaseSource::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException, std::exception)
557 : {
558 57 : if ( m_pImpl.is() )
559 35 : m_pImpl->disposing(Source);
560 57 : }
561 :
562 : // XServiceInfo
563 2 : OUString ODatabaseSource::getImplementationName( ) throw(RuntimeException, std::exception)
564 : {
565 2 : return getImplementationName_static();
566 : }
567 :
568 22 : OUString ODatabaseSource::getImplementationName_static( ) throw(RuntimeException)
569 : {
570 22 : return OUString("com.sun.star.comp.dba.ODatabaseSource");
571 : }
572 :
573 1 : Sequence< OUString > ODatabaseSource::getSupportedServiceNames( ) throw (RuntimeException, std::exception)
574 : {
575 1 : return getSupportedServiceNames_static();
576 : }
577 :
578 82 : Reference< XInterface > ODatabaseSource::Create( const Reference< XComponentContext >& _rxContext )
579 : {
580 82 : Reference< XDatabaseContext > xDBContext( DatabaseContext::create(_rxContext) );
581 82 : return xDBContext->createInstance();
582 : }
583 :
584 21 : Sequence< OUString > ODatabaseSource::getSupportedServiceNames_static( ) throw (RuntimeException)
585 : {
586 21 : Sequence< OUString > aSNS( 2 );
587 21 : aSNS[0] = SERVICE_SDB_DATASOURCE;
588 21 : aSNS[1] = "com.sun.star.sdb.DocumentDataSource";
589 21 : return aSNS;
590 : }
591 :
592 0 : sal_Bool ODatabaseSource::supportsService( const OUString& _rServiceName ) throw (RuntimeException, std::exception)
593 : {
594 0 : return cppu::supportsService(this, _rServiceName);
595 : }
596 :
597 : // OComponentHelper
598 255 : void ODatabaseSource::disposing()
599 : {
600 : SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
601 255 : ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
602 255 : OPropertySetHelper::disposing();
603 :
604 255 : EventObject aDisposeEvent(static_cast<XWeak*>(this));
605 255 : m_aFlushListeners.disposeAndClear( aDisposeEvent );
606 :
607 255 : ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
608 255 : ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
609 255 : m_pImpl.clear();
610 255 : }
611 :
612 47 : Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
613 : {
614 47 : Reference< XConnection > xReturn;
615 :
616 94 : Reference< XDriverManager > xManager;
617 : try {
618 47 : xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
619 1 : } catch( const Exception& ) { }
620 47 : if ( !xManager.is() )
621 : // no connection pool installed, fall back to driver manager
622 1 : xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
623 :
624 94 : OUString sUser(_rUid);
625 94 : OUString sPwd(_rPwd);
626 47 : if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty()))
627 : { // ease the usage of this method. data source which are intended to have a user automatically
628 : // fill in the user/password combination if the caller of this method does not specify otherwise
629 0 : sUser = m_pImpl->m_sUser;
630 0 : if (!m_pImpl->m_aPassword.isEmpty())
631 0 : sPwd = m_pImpl->m_aPassword;
632 : }
633 :
634 47 : sal_uInt16 nExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
635 47 : if (xManager.is())
636 : {
637 47 : sal_Int32 nAdditionalArgs(0);
638 47 : if (!sUser.isEmpty()) ++nAdditionalArgs;
639 47 : if (!sPwd.isEmpty()) ++nAdditionalArgs;
640 :
641 47 : Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
642 47 : sal_Int32 nArgPos = 0;
643 47 : if (!sUser.isEmpty())
644 : {
645 1 : aUserPwd[ nArgPos ].Name = "user";
646 1 : aUserPwd[ nArgPos ].Value <<= sUser;
647 1 : ++nArgPos;
648 : }
649 47 : if (!sPwd.isEmpty())
650 : {
651 1 : aUserPwd[ nArgPos ].Name = "password";
652 1 : aUserPwd[ nArgPos ].Value <<= sPwd;
653 : }
654 94 : Reference< XDriver > xDriver;
655 : try
656 : {
657 47 : Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
658 47 : if ( xAccessDrivers.is() )
659 47 : xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
660 : }
661 0 : catch( const Exception& )
662 : {
663 : SAL_WARN("dbaccess", "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error!" );
664 : }
665 47 : if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
666 : {
667 : // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
668 : // This is because registration nowadays happens at compile time (by adding respective configuration data),
669 : // but acceptance is decided at runtime.
670 0 : nExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
671 : }
672 : else
673 : {
674 : Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
675 : xDriver,
676 47 : m_pImpl->m_sConnectURL,
677 94 : m_pImpl->m_xSettings->getPropertyValues(),
678 : dbaccess::ODatabaseModelImpl::getDefaultDataSourceSettings()
679 188 : );
680 :
681 47 : if ( m_pImpl->isEmbeddedDatabase() )
682 : {
683 9 : sal_Int32 nCount = aDriverInfo.getLength();
684 9 : aDriverInfo.realloc(nCount + 3 );
685 :
686 9 : aDriverInfo[nCount].Name = "URL";
687 9 : aDriverInfo[nCount++].Value <<= m_pImpl->getURL();
688 :
689 9 : aDriverInfo[nCount].Name = "Storage";
690 9 : Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
691 9 : aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE);
692 :
693 9 : aDriverInfo[nCount].Name = "Document";
694 9 : aDriverInfo[nCount++].Value <<= getDatabaseDocument();
695 : }
696 47 : if (nAdditionalArgs)
697 1 : xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
698 : else
699 46 : xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
700 :
701 47 : if ( m_pImpl->isEmbeddedDatabase() )
702 : {
703 : // see ODatabaseSource::flushed for comment on why we register as FlushListener
704 : // at the connection
705 9 : Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
706 9 : if ( xFlushable.is() )
707 9 : FlushNotificationAdapter::installAdapter( xFlushable, this );
708 47 : }
709 47 : }
710 : }
711 : else
712 0 : nExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
713 :
714 47 : if ( !xReturn.is() )
715 : {
716 : OUString sMessage = DBACORE_RESSTRING( nExceptionMessageId )
717 0 : .replaceAll("$name$", m_pImpl->m_sConnectURL);
718 :
719 0 : SQLContext aContext;
720 0 : aContext.Message = DBACORE_RESSTRING(RID_STR_CONNECTION_REQUEST).
721 0 : replaceFirst("$name$", m_pImpl->m_sConnectURL);
722 :
723 0 : throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), makeAny( aContext ) );
724 : }
725 :
726 94 : return xReturn;
727 : }
728 :
729 : // OPropertySetHelper
730 450 : Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo() throw (RuntimeException, std::exception)
731 : {
732 450 : return createPropertySetInfo( getInfoHelper() ) ;
733 : }
734 :
735 : // comphelper::OPropertyArrayUsageHelper
736 65 : ::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
737 : {
738 65 : BEGIN_PROPERTY_HELPER(13)
739 65 : DECL_PROP1(INFO, Sequence< PropertyValue >, BOUND);
740 65 : DECL_PROP1_BOOL(ISPASSWORDREQUIRED, BOUND);
741 65 : DECL_PROP1_BOOL(ISREADONLY, READONLY);
742 65 : DECL_PROP1(LAYOUTINFORMATION, Sequence< PropertyValue >, BOUND);
743 65 : DECL_PROP1(NAME, OUString, READONLY);
744 65 : DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier, READONLY, TRANSIENT);
745 65 : DECL_PROP1(PASSWORD, OUString, TRANSIENT);
746 65 : DECL_PROP2_IFACE(SETTINGS, XPropertySet, BOUND, READONLY);
747 65 : DECL_PROP1_BOOL(SUPPRESSVERSIONCL, BOUND);
748 65 : DECL_PROP1(TABLEFILTER, Sequence< OUString >,BOUND);
749 65 : DECL_PROP1(TABLETYPEFILTER, Sequence< OUString >,BOUND);
750 65 : DECL_PROP1(URL, OUString, BOUND);
751 65 : DECL_PROP1(USER, OUString, BOUND);
752 65 : END_PROPERTY_HELPER();
753 : }
754 :
755 : // cppu::OPropertySetHelper
756 8486 : ::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
757 : {
758 8486 : return *getArrayHelper();
759 : }
760 :
761 243 : sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) throw( IllegalArgumentException )
762 : {
763 243 : bool bModified(false);
764 243 : if ( m_pImpl.is() )
765 : {
766 243 : switch (nHandle)
767 : {
768 : case PROPERTY_ID_TABLEFILTER:
769 16 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
770 16 : break;
771 : case PROPERTY_ID_TABLETYPEFILTER:
772 0 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
773 0 : break;
774 : case PROPERTY_ID_USER:
775 0 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
776 0 : break;
777 : case PROPERTY_ID_PASSWORD:
778 72 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
779 72 : break;
780 : case PROPERTY_ID_ISPASSWORDREQUIRED:
781 16 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
782 16 : break;
783 : case PROPERTY_ID_SUPPRESSVERSIONCL:
784 16 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
785 16 : break;
786 : case PROPERTY_ID_LAYOUTINFORMATION:
787 0 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
788 0 : break;
789 : case PROPERTY_ID_URL:
790 : {
791 107 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
792 107 : } break;
793 : case PROPERTY_ID_INFO:
794 : {
795 16 : Sequence<PropertyValue> aValues;
796 16 : if (!(rValue >>= aValues))
797 0 : throw IllegalArgumentException();
798 :
799 16 : const PropertyValue* valueEnd = aValues.getConstArray() + aValues.getLength();
800 16 : const PropertyValue* checkName = aValues.getConstArray();
801 144 : for ( ;checkName != valueEnd; ++checkName )
802 : {
803 128 : if ( checkName->Name.isEmpty() )
804 0 : throw IllegalArgumentException();
805 : }
806 :
807 32 : Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
808 16 : bModified = aSettings.getLength() != aValues.getLength();
809 16 : if ( !bModified )
810 : {
811 0 : const PropertyValue* pInfoIter = aSettings.getConstArray();
812 0 : const PropertyValue* checkValue = aValues.getConstArray();
813 0 : for ( ;!bModified && checkValue != valueEnd ; ++checkValue,++pInfoIter)
814 : {
815 0 : bModified = checkValue->Name != pInfoIter->Name;
816 0 : if ( !bModified )
817 : {
818 0 : bModified = !::comphelper::compare(checkValue->Value,pInfoIter->Value);
819 : }
820 : }
821 : }
822 :
823 16 : rConvertedValue = rValue;
824 32 : rOldValue <<= aSettings;
825 : }
826 16 : break;
827 : default:
828 : SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
829 : }
830 : }
831 243 : return bModified;
832 : }
833 :
834 : namespace
835 : {
836 : struct SelectPropertyName : public ::std::unary_function< PropertyValue, OUString >
837 : {
838 : public:
839 128 : const OUString& operator()( const PropertyValue& _lhs )
840 : {
841 128 : return _lhs.Name;
842 : }
843 : };
844 :
845 : /** sets a new set of property values for a given property bag instance
846 :
847 : The method takes a property bag, and a sequence of property values to set for this bag.
848 : Upon return, every property which is not part of the given sequence is
849 : <ul><li>removed from the bag, if it's a removable property</li>
850 : <li><em>or</em>reset to its default value, if it's not a removable property</li>
851 : </ul>.
852 :
853 : @param _rxPropertyBag
854 : the property bag to operate on
855 : @param _rAllNewPropertyValues
856 : the new property values to set for the bag
857 : */
858 16 : void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyBag >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
859 : {
860 : // sequences are ugly to operate on
861 : typedef ::std::set< OUString > StringSet;
862 16 : StringSet aToBeSetPropertyNames;
863 : ::std::transform(
864 : _rAllNewPropertyValues.getConstArray(),
865 16 : _rAllNewPropertyValues.getConstArray() + _rAllNewPropertyValues.getLength(),
866 : ::std::insert_iterator< StringSet >( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
867 : SelectPropertyName()
868 32 : );
869 :
870 : try
871 : {
872 : // obtain all properties currently known at the bag
873 16 : Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_QUERY_THROW );
874 32 : Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
875 :
876 32 : Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
877 :
878 : // loop through them, and reset resp. default properties which are not to be set
879 16 : const Property* pExistentProperty( aAllExistentProperties.getConstArray() );
880 16 : const Property* pExistentPropertyEnd( aAllExistentProperties.getConstArray() + aAllExistentProperties.getLength() );
881 864 : for ( ; pExistentProperty != pExistentPropertyEnd; ++pExistentProperty )
882 : {
883 848 : if ( aToBeSetPropertyNames.find( pExistentProperty->Name ) != aToBeSetPropertyNames.end() )
884 128 : continue;
885 :
886 : // this property is not to be set, but currently exists in the bag.
887 : // -> Remove it, or reset it to the default.
888 720 : if ( ( pExistentProperty->Attributes & PropertyAttribute::REMOVABLE ) != 0 )
889 0 : _rxPropertyBag->removeProperty( pExistentProperty->Name );
890 : else
891 720 : xPropertyState->setPropertyToDefault( pExistentProperty->Name );
892 : }
893 :
894 : // finally, set the new property values
895 32 : _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
896 : }
897 0 : catch( const Exception& )
898 : {
899 : DBG_UNHANDLED_EXCEPTION();
900 16 : }
901 16 : }
902 : }
903 :
904 132 : void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception, std::exception)
905 : {
906 132 : if ( m_pImpl.is() )
907 : {
908 132 : switch(nHandle)
909 : {
910 : case PROPERTY_ID_TABLEFILTER:
911 9 : rValue >>= m_pImpl->m_aTableFilter;
912 9 : break;
913 : case PROPERTY_ID_TABLETYPEFILTER:
914 0 : rValue >>= m_pImpl->m_aTableTypeFilter;
915 0 : break;
916 : case PROPERTY_ID_USER:
917 0 : rValue >>= m_pImpl->m_sUser;
918 : // if the user name has changed, reset the password
919 0 : (m_pImpl->m_aPassword).clear();
920 0 : break;
921 : case PROPERTY_ID_PASSWORD:
922 0 : rValue >>= m_pImpl->m_aPassword;
923 0 : break;
924 : case PROPERTY_ID_ISPASSWORDREQUIRED:
925 0 : m_pImpl->m_bPasswordRequired = any2bool(rValue);
926 0 : break;
927 : case PROPERTY_ID_SUPPRESSVERSIONCL:
928 0 : m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
929 0 : break;
930 : case PROPERTY_ID_URL:
931 107 : rValue >>= m_pImpl->m_sConnectURL;
932 107 : break;
933 : case PROPERTY_ID_INFO:
934 : {
935 16 : Sequence< PropertyValue > aInfo;
936 16 : OSL_VERIFY( rValue >>= aInfo );
937 16 : lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
938 : }
939 16 : break;
940 : case PROPERTY_ID_LAYOUTINFORMATION:
941 0 : rValue >>= m_pImpl->m_aLayoutInformation;
942 0 : break;
943 : }
944 132 : m_pImpl->setModified(true);
945 : }
946 132 : }
947 :
948 3682 : void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
949 : {
950 3682 : if ( m_pImpl.is() )
951 : {
952 3682 : switch (nHandle)
953 : {
954 : case PROPERTY_ID_TABLEFILTER:
955 152 : rValue <<= m_pImpl->m_aTableFilter;
956 152 : break;
957 : case PROPERTY_ID_TABLETYPEFILTER:
958 152 : rValue <<= m_pImpl->m_aTableTypeFilter;
959 152 : break;
960 : case PROPERTY_ID_USER:
961 115 : rValue <<= m_pImpl->m_sUser;
962 115 : break;
963 : case PROPERTY_ID_PASSWORD:
964 122 : rValue <<= m_pImpl->m_aPassword;
965 122 : break;
966 : case PROPERTY_ID_ISPASSWORDREQUIRED:
967 108 : rValue <<= m_pImpl->m_bPasswordRequired;
968 108 : break;
969 : case PROPERTY_ID_SUPPRESSVERSIONCL:
970 1 : rValue <<= m_pImpl->m_bSuppressVersionColumns;
971 1 : break;
972 : case PROPERTY_ID_ISREADONLY:
973 0 : rValue <<= m_pImpl->m_bReadOnly;
974 0 : break;
975 : case PROPERTY_ID_INFO:
976 : {
977 : try
978 : {
979 : // collect the property attributes of all current settings
980 104 : Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
981 208 : Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_QUERY_THROW );
982 208 : Sequence< Property > aSettings( xPST->getProperties() );
983 208 : ::std::map< OUString, sal_Int32 > aPropertyAttributes;
984 11232 : for ( const Property* pSettings = aSettings.getConstArray();
985 5616 : pSettings != aSettings.getConstArray() + aSettings.getLength();
986 : ++pSettings
987 : )
988 : {
989 5512 : aPropertyAttributes[ pSettings->Name ] = pSettings->Attributes;
990 : }
991 :
992 : // get all current settings with their values
993 208 : Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
994 :
995 : // transform them so that only property values which fulfill certain
996 : // criteria survive
997 208 : Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
998 : const PropertyValue* pCopyEnd = ::std::remove_copy_if(
999 : aValues.getConstArray(),
1000 104 : aValues.getConstArray() + aValues.getLength(),
1001 : aNonDefaultOrUserDefined.getArray(),
1002 : IsDefaultAndNotRemoveable( aPropertyAttributes )
1003 208 : );
1004 104 : aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() );
1005 208 : rValue <<= aNonDefaultOrUserDefined;
1006 : }
1007 0 : catch( const Exception& )
1008 : {
1009 : DBG_UNHANDLED_EXCEPTION();
1010 : }
1011 : }
1012 104 : break;
1013 : case PROPERTY_ID_SETTINGS:
1014 1387 : rValue <<= m_pImpl->m_xSettings;
1015 1387 : break;
1016 : case PROPERTY_ID_URL:
1017 253 : rValue <<= m_pImpl->m_sConnectURL;
1018 253 : break;
1019 : case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
1020 1173 : rValue <<= m_pImpl->getNumberFormatsSupplier();
1021 1173 : break;
1022 : case PROPERTY_ID_NAME:
1023 9 : rValue <<= m_pImpl->m_sName;
1024 9 : break;
1025 : case PROPERTY_ID_LAYOUTINFORMATION:
1026 106 : rValue <<= m_pImpl->m_aLayoutInformation;
1027 106 : break;
1028 : default:
1029 : SAL_WARN("dbaccess","unknown Property");
1030 : }
1031 : }
1032 3682 : }
1033 :
1034 : // XDataSource
1035 1 : void ODatabaseSource::setLoginTimeout(sal_Int32 seconds) throw( SQLException, RuntimeException, std::exception )
1036 : {
1037 1 : ModelMethodGuard aGuard( *this );
1038 1 : m_pImpl->m_nLoginTimeout = seconds;
1039 1 : }
1040 :
1041 2 : sal_Int32 ODatabaseSource::getLoginTimeout() throw( SQLException, RuntimeException, std::exception )
1042 : {
1043 2 : ModelMethodGuard aGuard( *this );
1044 2 : return m_pImpl->m_nLoginTimeout;
1045 : }
1046 :
1047 : // XCompletedConnection
1048 5 : Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
1049 : {
1050 5 : return connectWithCompletion(_rxHandler,false);
1051 : }
1052 :
1053 43 : Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password) throw( SQLException, RuntimeException, std::exception )
1054 : {
1055 43 : return getConnection(user,password,false);
1056 : }
1057 :
1058 1 : Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const OUString& user, const OUString& password ) throw(SQLException, RuntimeException, std::exception)
1059 : {
1060 1 : return getConnection(user,password,true);
1061 : }
1062 :
1063 1 : Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
1064 : {
1065 1 : return connectWithCompletion(_rxHandler,true);
1066 : }
1067 :
1068 6 : Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,bool _bIsolated ) throw(SQLException, RuntimeException)
1069 : {
1070 6 : ModelMethodGuard aGuard( *this );
1071 :
1072 6 : if (!_rxHandler.is())
1073 : {
1074 : SAL_WARN("dbaccess","ODatabaseSource::connectWithCompletion: invalid interaction handler!");
1075 0 : return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
1076 : }
1077 :
1078 12 : OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
1079 6 : bool bNewPasswordGiven = false;
1080 :
1081 6 : if (m_pImpl->m_bPasswordRequired && sPassword.isEmpty())
1082 : { // we need a password, but don't have one yet.
1083 : // -> ask the user
1084 :
1085 : // build an interaction request
1086 : // two continuations (Ok and Cancel)
1087 0 : OInteractionAbort* pAbort = new OInteractionAbort;
1088 0 : OAuthenticationContinuation* pAuthenticate = new OAuthenticationContinuation;
1089 :
1090 : // the name which should be referred in the login dialog
1091 0 : OUString sServerName( m_pImpl->m_sName );
1092 0 : INetURLObject aURLCheck( sServerName );
1093 0 : if ( aURLCheck.GetProtocol() != INetProtocol::NotValid )
1094 0 : sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_UNAMBIGUOUS );
1095 :
1096 : // the request
1097 0 : AuthenticationRequest aRequest;
1098 0 : aRequest.ServerName = sServerName;
1099 0 : aRequest.HasRealm = aRequest.HasAccount = sal_False;
1100 0 : aRequest.HasUserName = aRequest.HasPassword = sal_True;
1101 0 : aRequest.UserName = m_pImpl->m_sUser;
1102 0 : aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ? m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword;
1103 0 : OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest));
1104 0 : Reference< XInteractionRequest > xRequest(pRequest);
1105 : // some knittings
1106 0 : pRequest->addContinuation(pAbort);
1107 0 : pRequest->addContinuation(pAuthenticate);
1108 :
1109 : // handle the request
1110 : try
1111 : {
1112 0 : MutexRelease aRelease( getMutex() );
1113 : // release the mutex when calling the handler, it may need to lock the SolarMutex
1114 0 : _rxHandler->handle(xRequest);
1115 : }
1116 0 : catch(Exception&)
1117 : {
1118 : DBG_UNHANDLED_EXCEPTION();
1119 : }
1120 :
1121 0 : if (!pAuthenticate->wasSelected())
1122 0 : return Reference< XConnection >();
1123 :
1124 : // get the result
1125 0 : sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
1126 0 : sPassword = pAuthenticate->getPassword();
1127 :
1128 0 : if (pAuthenticate->getRememberPassword())
1129 : {
1130 0 : m_pImpl->m_aPassword = pAuthenticate->getPassword();
1131 0 : bNewPasswordGiven = true;
1132 : }
1133 0 : (m_pImpl->m_sFailedPassword).clear();
1134 : }
1135 :
1136 : try
1137 : {
1138 6 : return getConnection(sUser, sPassword,_bIsolated);
1139 : }
1140 0 : catch(Exception&)
1141 : {
1142 0 : if (bNewPasswordGiven)
1143 : {
1144 0 : m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
1145 : // assume that we had an authentication problem. Without this we may, after an unsuccessful connect, while
1146 : // the user gave us a password an the order to remember it, never allow an password input again (at least
1147 : // not without restarting the session)
1148 0 : (m_pImpl->m_aPassword).clear();
1149 : }
1150 0 : throw;
1151 6 : }
1152 : }
1153 :
1154 47 : Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
1155 : {
1156 47 : Reference< XConnection > xConn;
1157 94 : Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
1158 : OSL_ENSURE( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
1159 : // buildLowLevelConnection is expected to always succeed
1160 47 : if ( xSdbcConn.is() )
1161 : {
1162 : // build a connection server and return it (no stubs)
1163 47 : xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
1164 : }
1165 94 : return xConn;
1166 : }
1167 :
1168 50 : Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,bool _bIsolated) throw( SQLException, RuntimeException )
1169 : {
1170 50 : ModelMethodGuard aGuard( *this );
1171 :
1172 50 : Reference< XConnection > xConn;
1173 50 : if ( _bIsolated )
1174 : {
1175 2 : xConn = buildIsolatedConnection(user,password);
1176 : }
1177 : else
1178 : { // create a new proxy for the connection
1179 48 : if ( !m_pImpl->m_xSharedConnectionManager.is() )
1180 : {
1181 40 : m_pImpl->m_pSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext );
1182 40 : m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
1183 : }
1184 192 : xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
1185 192 : m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
1186 : }
1187 :
1188 50 : if ( xConn.is() )
1189 : {
1190 50 : Reference< XComponent> xComp(xConn,UNO_QUERY);
1191 50 : if ( xComp.is() )
1192 50 : xComp->addEventListener( static_cast< XContainerListener* >( this ) );
1193 50 : m_pImpl->m_aConnections.push_back(OWeakConnection(xConn));
1194 : }
1195 :
1196 50 : return xConn;
1197 : }
1198 :
1199 1 : Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( ) throw (RuntimeException, std::exception)
1200 : {
1201 1 : ModelMethodGuard aGuard( *this );
1202 1 : return static_cast< XNameContainer* >(&m_aBookmarks);
1203 : }
1204 :
1205 390 : Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( ) throw(RuntimeException, std::exception)
1206 : {
1207 390 : ModelMethodGuard aGuard( *this );
1208 :
1209 390 : Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
1210 390 : if ( !xContainer.is() )
1211 : {
1212 331 : Any aValue;
1213 662 : ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xMy(*this);
1214 331 : if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
1215 : {
1216 331 : OUString sSupportService;
1217 331 : aValue >>= sSupportService;
1218 331 : if ( !sSupportService.isEmpty() )
1219 : {
1220 0 : Sequence<Any> aArgs(1);
1221 0 : aArgs[0] <<= NamedValue("DataSource",makeAny(xMy));
1222 0 : xContainer.set( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext), UNO_QUERY);
1223 331 : }
1224 : }
1225 331 : if ( !xContainer.is() )
1226 : {
1227 331 : TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
1228 331 : xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false );
1229 : }
1230 662 : m_pImpl->m_xCommandDefinitions = xContainer;
1231 : }
1232 390 : return xContainer;
1233 : }
1234 :
1235 : // XTablesSupplier
1236 252 : Reference< XNameAccess > ODatabaseSource::getTables() throw( RuntimeException, std::exception )
1237 : {
1238 252 : ModelMethodGuard aGuard( *this );
1239 :
1240 252 : Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
1241 252 : if ( !xContainer.is() )
1242 : {
1243 245 : TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) );
1244 245 : xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, true );
1245 245 : m_pImpl->m_xTableDefinitions = xContainer;
1246 : }
1247 252 : return xContainer;
1248 : }
1249 :
1250 1 : void SAL_CALL ODatabaseSource::flush( ) throw (RuntimeException, std::exception)
1251 : {
1252 : try
1253 : {
1254 : // SYNCHRONIZED ->
1255 : {
1256 1 : ModelMethodGuard aGuard( *this );
1257 :
1258 : typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
1259 2 : SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
1260 :
1261 1 : if ( !xModel.is() )
1262 0 : xModel.reset( m_pImpl->createNewModel_deliverOwnership( false ), SharedModel::TakeOwnership );
1263 :
1264 2 : Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
1265 2 : xStorable->store();
1266 : }
1267 : // <- SYNCHRONIZED
1268 :
1269 1 : css::lang::EventObject aFlushedEvent(*this);
1270 1 : m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
1271 : }
1272 0 : catch( const Exception& )
1273 : {
1274 : DBG_UNHANDLED_EXCEPTION();
1275 : }
1276 1 : }
1277 :
1278 6 : void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ ) throw (RuntimeException, std::exception)
1279 : {
1280 6 : ModelMethodGuard aGuard( *this );
1281 :
1282 : // Okay, this is some hack.
1283 : //
1284 : // In general, we have the problem that embedded databases write into their underlying storage, which
1285 : // logically is one of our sub storage, and practically is a temporary file maintained by the
1286 : // package implementation. As long as we did not commit this storage and our main storage,
1287 : // the changes made by the embedded database engine are not really reflected in the database document
1288 : // file. This is Bad (TM) for a "real" database application - imagine somebody entering some
1289 : // data, and then crashing: For a database application, you would expect that the data still is present
1290 : // when you connect to the database next time.
1291 : //
1292 : // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot*
1293 : // provide the desired functionality as long as we do not have a package format which allows O(1) writes),
1294 : // we cannot completely fix this. However, we can relax the problem by committing more often - often
1295 : // enough so that data loss is more seldom, and seldom enough so that there's no noticeable performance
1296 : // decrease.
1297 : //
1298 : // For this, we introduced a few places which XFlushable::flush their connections, and register as
1299 : // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality).
1300 : // Then, when the connection is flushed, we commit both the database storage and our main storage.
1301 : //
1302 : // #i55274#
1303 :
1304 : OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" );
1305 6 : bool bWasModified = m_pImpl->m_bModified;
1306 6 : m_pImpl->commitEmbeddedStorage();
1307 6 : m_pImpl->setModified( bWasModified );
1308 6 : }
1309 :
1310 2 : void SAL_CALL ODatabaseSource::addFlushListener( const Reference< ::com::sun::star::util::XFlushListener >& _xListener ) throw (RuntimeException, std::exception)
1311 : {
1312 2 : m_aFlushListeners.addInterface(_xListener);
1313 2 : }
1314 :
1315 1 : void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< ::com::sun::star::util::XFlushListener >& _xListener ) throw (RuntimeException, std::exception)
1316 : {
1317 1 : m_aFlushListeners.removeInterface(_xListener);
1318 1 : }
1319 :
1320 0 : void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1321 : {
1322 0 : ModelMethodGuard aGuard( *this );
1323 0 : if ( m_pImpl.is() )
1324 0 : m_pImpl->setModified(true);
1325 0 : }
1326 :
1327 0 : void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1328 : {
1329 0 : ModelMethodGuard aGuard( *this );
1330 0 : if ( m_pImpl.is() )
1331 0 : m_pImpl->setModified(true);
1332 0 : }
1333 :
1334 0 : void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1335 : {
1336 0 : ModelMethodGuard aGuard( *this );
1337 0 : if ( m_pImpl.is() )
1338 0 : m_pImpl->setModified(true);
1339 0 : }
1340 :
1341 : // XDocumentDataSource
1342 1476 : Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument() throw (RuntimeException, std::exception)
1343 : {
1344 1476 : ModelMethodGuard aGuard( *this );
1345 :
1346 2952 : Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
1347 1476 : if ( !xModel.is() )
1348 92 : xModel = m_pImpl->createNewModel_deliverOwnership( false );
1349 :
1350 2952 : return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
1351 : }
1352 :
1353 0 : Reference< XInterface > ODatabaseSource::getThis() const
1354 : {
1355 0 : return *const_cast< ODatabaseSource* >( this );
1356 : }
1357 :
1358 : } // namespace dbaccess
1359 :
1360 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|