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