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 0 : static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
117 : {
118 0 : Reference< XFlushListener > xAdapter( new FlushNotificationAdapter( _rxBroadcaster, _rxListener ) );
119 0 : }
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 0 : FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
135 : :m_aBroadcaster( _rxBroadcaster )
136 0 : ,m_aListener( _rxListener )
137 : {
138 : OSL_ENSURE( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
139 :
140 0 : osl_atomic_increment( &m_refCount );
141 : {
142 0 : if ( _rxBroadcaster.is() )
143 0 : _rxBroadcaster->addFlushListener( this );
144 : }
145 0 : osl_atomic_decrement( &m_refCount );
146 : OSL_ENSURE( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
147 0 : }
148 :
149 0 : FlushNotificationAdapter::~FlushNotificationAdapter()
150 : {
151 0 : }
152 :
153 0 : void SAL_CALL FlushNotificationAdapter::impl_dispose( bool _bRevokeListener )
154 : {
155 0 : Reference< XFlushListener > xKeepAlive( this );
156 :
157 0 : if ( _bRevokeListener )
158 : {
159 0 : Reference< XFlushable > xFlushable( m_aBroadcaster );
160 0 : if ( xFlushable.is() )
161 0 : xFlushable->removeFlushListener( this );
162 : }
163 :
164 0 : m_aListener.clear();
165 0 : m_aBroadcaster.clear();
166 0 : }
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 0 : void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source ) throw (RuntimeException, std::exception)
178 : {
179 0 : Reference< XFlushListener > xListener( m_aListener );
180 0 : if ( xListener.is() )
181 0 : xListener->disposing( Source );
182 :
183 0 : impl_dispose( true );
184 0 : }
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 0 : TDigestHolder()
268 : {
269 0 : m_pBuffer[0] = 0;
270 0 : }
271 :
272 : };
273 :
274 : class OSharedConnectionManager : public OConnectionHelper_BASE
275 : {
276 :
277 : // contains the currently used master connections
278 : typedef struct
279 0 : {
280 : Reference< XConnection > xMasterConnection;
281 : oslInterlockedCount nALiveCount;
282 0 : } TConnectionHolder;
283 :
284 : // the less-compare functor, used for the stl::map
285 : struct TDigestLess : public ::std::binary_function< TDigestHolder, TDigestHolder, bool>
286 : {
287 0 : bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
288 : {
289 : sal_uInt32 i;
290 0 : for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
291 : ;
292 0 : 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 0 : OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
320 : {
321 0 : m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
322 0 : }
323 :
324 0 : OSharedConnectionManager::~OSharedConnectionManager()
325 : {
326 0 : }
327 :
328 0 : void SAL_CALL OSharedConnectionManager::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException, std::exception)
329 : {
330 0 : MutexGuard aGuard(m_aMutex);
331 0 : Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
332 0 : TSharedConnectionMap::iterator aFind = m_aSharedConnection.find(xConnection);
333 0 : if ( m_aSharedConnection.end() != aFind )
334 : {
335 0 : osl_atomic_decrement(&aFind->second->second.nALiveCount);
336 0 : if ( !aFind->second->second.nALiveCount )
337 : {
338 0 : ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
339 0 : m_aConnections.erase(aFind->second);
340 : }
341 0 : m_aSharedConnection.erase(aFind);
342 0 : }
343 0 : }
344 :
345 0 : 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 0 : MutexGuard aGuard(m_aMutex);
352 0 : TConnectionMap::key_type nId;
353 0 : Sequence< PropertyValue > aInfoCopy(_aInfo);
354 0 : sal_Int32 nPos = aInfoCopy.getLength();
355 0 : aInfoCopy.realloc( nPos + 2 );
356 0 : aInfoCopy[nPos].Name = "TableFilter";
357 0 : aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
358 0 : aInfoCopy[nPos].Name = "TableTypeFilter";
359 0 : aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
360 :
361 0 : OUString sUser = user;
362 0 : OUString sPassword = password;
363 0 : 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 0 : ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
372 0 : TConnectionMap::iterator aIter = m_aConnections.find(nId);
373 :
374 0 : if ( m_aConnections.end() == aIter )
375 : {
376 0 : TConnectionHolder aHolder;
377 0 : aHolder.nALiveCount = 0; // will be incremented by addListener
378 0 : aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
379 0 : aIter = m_aConnections.insert(TConnectionMap::value_type(nId,aHolder)).first;
380 : }
381 :
382 0 : Reference<XConnection> xRet;
383 0 : if ( aIter->second.xMasterConnection.is() )
384 : {
385 0 : Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection.get());
386 0 : xRet = new OSharedConnection(xConProxy);
387 0 : m_aSharedConnection.insert(TSharedConnectionMap::value_type(xRet,aIter));
388 0 : addEventListener(xRet,aIter);
389 : }
390 :
391 0 : return xRet;
392 : }
393 :
394 0 : void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter)
395 : {
396 0 : Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
397 0 : xComp->addEventListener(this);
398 : OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
399 0 : osl_atomic_increment(&_rIter->second.nALiveCount);
400 0 : }
401 :
402 : namespace
403 : {
404 0 : Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
405 : const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
406 : {
407 0 : if ( _xDriver.is() )
408 : {
409 0 : Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
410 :
411 0 : const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
412 0 : const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
413 :
414 0 : ::std::vector< PropertyValue > aRet;
415 :
416 0 : for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
417 : {
418 0 : sal_Bool bAllowSetting = sal_False;
419 0 : const AsciiPropertyValue* pSetting = _pKnownSettings;
420 0 : for ( ; pSetting->AsciiName; ++pSetting )
421 : {
422 0 : if ( pDataSourceSetting->Name.equalsAscii( pSetting->AsciiName ) )
423 : { // the particular data source setting is known
424 :
425 0 : const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
426 0 : const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
427 0 : for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
428 : {
429 0 : if ( pAllowedDriverSetting->Name.equalsAscii( pSetting->AsciiName ) )
430 : { // the driver also allows this setting
431 0 : bAllowSetting = sal_True;
432 0 : break;
433 : }
434 : }
435 0 : break;
436 : }
437 : }
438 0 : 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 0 : aRet.push_back( *pDataSourceSetting );
442 : }
443 : }
444 0 : if ( !aRet.empty() )
445 0 : return Sequence< PropertyValue >(&(*aRet.begin()),aRet.size());
446 : }
447 0 : 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 0 : IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
459 :
460 0 : bool operator()( const PropertyValue& _rProp )
461 : {
462 0 : if ( _rProp.State != PropertyState_DEFAULT_VALUE )
463 0 : return false;
464 :
465 0 : bool bRemoveable = true;
466 :
467 0 : PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
468 : OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
469 0 : if ( pos != m_rAttribs.end() )
470 0 : bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
471 :
472 0 : return !bRemoveable;
473 : }
474 : };
475 : }
476 :
477 : // ODatabaseContext
478 :
479 0 : extern "C" void SAL_CALL createRegistryInfo_ODatabaseSource()
480 : {
481 0 : static ::dba::OAutoRegistration< ODatabaseSource > aAutoRegistration;
482 0 : }
483 :
484 0 : ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
485 : :ModelDependentComponent( _pImpl )
486 0 : ,ODatabaseSource_Base( getMutex() )
487 : ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
488 0 : ,m_aBookmarks( *this, getMutex() )
489 0 : ,m_aFlushListeners( getMutex() )
490 : {
491 : // some kind of default
492 : SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
493 0 : }
494 :
495 0 : ODatabaseSource::~ODatabaseSource()
496 : {
497 : SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
498 0 : if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
499 : {
500 0 : acquire();
501 0 : dispose();
502 : }
503 0 : }
504 :
505 0 : void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
506 : {
507 : SAL_INFO("dbaccess", "ODatabaseSource::setName" );
508 0 : ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument.get() );
509 :
510 0 : ::osl::MutexGuard aGuard( rModelImpl.m_aMutex );
511 0 : if ( rModelImpl.m_pImpl.is() )
512 0 : rModelImpl.m_pImpl->m_sName = _rNewName;
513 0 : }
514 :
515 : // com::sun::star::lang::XTypeProvider
516 0 : Sequence< Type > ODatabaseSource::getTypes() throw (RuntimeException, std::exception)
517 : {
518 : SAL_INFO("dbaccess", "ODatabaseSource::getTypes" );
519 0 : OTypeCollection aPropertyHelperTypes( ::getCppuType( (const Reference< XFastPropertySet > *)0 ),
520 0 : ::getCppuType( (const Reference< XPropertySet > *)0 ),
521 0 : ::getCppuType( (const Reference< XMultiPropertySet > *)0 ));
522 :
523 : return ::comphelper::concatSequences(
524 : ODatabaseSource_Base::getTypes(),
525 : aPropertyHelperTypes.getTypes()
526 0 : );
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 0 : Any ODatabaseSource::queryInterface( const Type & rType ) throw (RuntimeException, std::exception)
536 : {
537 0 : Any aIface = ODatabaseSource_Base::queryInterface( rType );
538 0 : if ( !aIface.hasValue() )
539 0 : aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
540 0 : return aIface;
541 : }
542 :
543 0 : void ODatabaseSource::acquire() throw ()
544 : {
545 0 : ODatabaseSource_Base::acquire();
546 0 : }
547 :
548 0 : void ODatabaseSource::release() throw ()
549 : {
550 0 : ODatabaseSource_Base::release();
551 0 : }
552 :
553 0 : void SAL_CALL ODatabaseSource::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException, std::exception)
554 : {
555 0 : if ( m_pImpl.is() )
556 0 : m_pImpl->disposing(Source);
557 0 : }
558 :
559 : // XServiceInfo
560 0 : OUString ODatabaseSource::getImplementationName( ) throw(RuntimeException, std::exception)
561 : {
562 : SAL_INFO("dbaccess", "ODatabaseSource::getImplementationName" );
563 0 : return getImplementationName_static();
564 : }
565 :
566 0 : OUString ODatabaseSource::getImplementationName_static( ) throw(RuntimeException)
567 : {
568 : SAL_INFO("dbaccess", "ODatabaseSource::getImplementationName_static" );
569 0 : 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 0 : Reference< XInterface > ODatabaseSource::Create( const Reference< XComponentContext >& _rxContext )
579 : {
580 : SAL_INFO("dbaccess", "ODatabaseSource::Create" );
581 0 : Reference< XDatabaseContext > xDBContext( DatabaseContext::create(_rxContext) );
582 0 : return xDBContext->createInstance();
583 : }
584 :
585 0 : Sequence< OUString > ODatabaseSource::getSupportedServiceNames_static( ) throw (RuntimeException)
586 : {
587 : SAL_INFO("dbaccess", "ODatabaseSource::getSupportedServiceNames_static" );
588 0 : Sequence< OUString > aSNS( 2 );
589 0 : aSNS[0] = SERVICE_SDB_DATASOURCE;
590 0 : aSNS[1] = "com.sun.star.sdb.DocumentDataSource";
591 0 : 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 0 : void ODatabaseSource::disposing()
601 : {
602 : SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
603 0 : ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
604 0 : OPropertySetHelper::disposing();
605 :
606 0 : EventObject aDisposeEvent(static_cast<XWeak*>(this));
607 0 : m_aFlushListeners.disposeAndClear( aDisposeEvent );
608 :
609 0 : ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
610 0 : ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
611 0 : m_pImpl.clear();
612 0 : }
613 :
614 0 : Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
615 : {
616 : SAL_INFO("dbaccess", "ODatabaseSource::buildLowLevelConnection" );
617 0 : Reference< XConnection > xReturn;
618 :
619 0 : Reference< XDriverManager > xManager;
620 : try {
621 0 : xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
622 0 : } catch( const Exception& ) { }
623 0 : if ( !xManager.is() )
624 : // no connection pool installed, fall back to driver manager
625 0 : xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
626 :
627 0 : OUString sUser(_rUid);
628 0 : OUString sPwd(_rPwd);
629 0 : 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 0 : sal_uInt16 nExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
638 0 : if (xManager.is())
639 : {
640 0 : sal_Int32 nAdditionalArgs(0);
641 0 : if (!sUser.isEmpty()) ++nAdditionalArgs;
642 0 : if (!sPwd.isEmpty()) ++nAdditionalArgs;
643 :
644 0 : Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
645 0 : sal_Int32 nArgPos = 0;
646 0 : if (!sUser.isEmpty())
647 : {
648 0 : aUserPwd[ nArgPos ].Name = "user";
649 0 : aUserPwd[ nArgPos ].Value <<= sUser;
650 0 : ++nArgPos;
651 : }
652 0 : if (!sPwd.isEmpty())
653 : {
654 0 : aUserPwd[ nArgPos ].Name = "password";
655 0 : aUserPwd[ nArgPos ].Value <<= sPwd;
656 : }
657 0 : Reference< XDriver > xDriver;
658 : try
659 : {
660 0 : Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
661 0 : if ( xAccessDrivers.is() )
662 0 : 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 0 : 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 0 : m_pImpl->m_sConnectURL,
680 0 : m_pImpl->m_xSettings->getPropertyValues(),
681 0 : m_pImpl->getDefaultDataSourceSettings()
682 0 : );
683 :
684 0 : if ( m_pImpl->isEmbeddedDatabase() )
685 : {
686 0 : sal_Int32 nCount = aDriverInfo.getLength();
687 0 : aDriverInfo.realloc(nCount + 3 );
688 :
689 0 : aDriverInfo[nCount].Name = "URL";
690 0 : aDriverInfo[nCount++].Value <<= m_pImpl->getURL();
691 :
692 0 : aDriverInfo[nCount].Name = "Storage";
693 0 : Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
694 0 : aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE);
695 :
696 0 : aDriverInfo[nCount].Name = "Document";
697 0 : aDriverInfo[nCount++].Value <<= getDatabaseDocument();
698 : }
699 0 : if (nAdditionalArgs)
700 0 : xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
701 : else
702 0 : xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
703 :
704 0 : if ( m_pImpl->isEmbeddedDatabase() )
705 : {
706 : // see ODatabaseSource::flushed for comment on why we register as FlushListener
707 : // at the connection
708 0 : Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
709 0 : if ( xFlushable.is() )
710 0 : FlushNotificationAdapter::installAdapter( xFlushable, this );
711 0 : }
712 0 : }
713 : }
714 : else
715 0 : nExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
716 :
717 0 : 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 0 : return xReturn;
730 : }
731 :
732 : // OPropertySetHelper
733 0 : Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo() throw (RuntimeException, std::exception)
734 : {
735 : SAL_INFO("dbaccess", "ODatabaseSource::getPropertySetInfo" );
736 0 : return createPropertySetInfo( getInfoHelper() ) ;
737 : }
738 :
739 : // comphelper::OPropertyArrayUsageHelper
740 0 : ::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
741 : {
742 : SAL_INFO("dbaccess", "ODatabaseSource::createArrayHelper" );
743 0 : BEGIN_PROPERTY_HELPER(13)
744 0 : DECL_PROP1(INFO, Sequence< PropertyValue >, BOUND);
745 0 : DECL_PROP1_BOOL(ISPASSWORDREQUIRED, BOUND);
746 0 : DECL_PROP1_BOOL(ISREADONLY, READONLY);
747 0 : DECL_PROP1(LAYOUTINFORMATION, Sequence< PropertyValue >, BOUND);
748 0 : DECL_PROP1(NAME, OUString, READONLY);
749 0 : DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier, READONLY, TRANSIENT);
750 0 : DECL_PROP1(PASSWORD, OUString, TRANSIENT);
751 0 : DECL_PROP2_IFACE(SETTINGS, XPropertySet, BOUND, READONLY);
752 0 : DECL_PROP1_BOOL(SUPPRESSVERSIONCL, BOUND);
753 0 : DECL_PROP1(TABLEFILTER, Sequence< OUString >,BOUND);
754 0 : DECL_PROP1(TABLETYPEFILTER, Sequence< OUString >,BOUND);
755 0 : DECL_PROP1(URL, OUString, BOUND);
756 0 : DECL_PROP1(USER, OUString, BOUND);
757 0 : END_PROPERTY_HELPER();
758 : }
759 :
760 : // cppu::OPropertySetHelper
761 0 : ::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
762 : {
763 0 : return *getArrayHelper();
764 : }
765 :
766 0 : sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) throw( IllegalArgumentException )
767 : {
768 0 : sal_Bool bModified(sal_False);
769 0 : if ( m_pImpl.is() )
770 : {
771 0 : switch (nHandle)
772 : {
773 : case PROPERTY_ID_TABLEFILTER:
774 0 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
775 0 : 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 0 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
784 0 : break;
785 : case PROPERTY_ID_ISPASSWORDREQUIRED:
786 0 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
787 0 : break;
788 : case PROPERTY_ID_SUPPRESSVERSIONCL:
789 0 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
790 0 : 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 0 : bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
797 0 : } break;
798 : case PROPERTY_ID_INFO:
799 : {
800 0 : Sequence<PropertyValue> aValues;
801 0 : if (!(rValue >>= aValues))
802 0 : throw IllegalArgumentException();
803 :
804 0 : const PropertyValue* valueEnd = aValues.getConstArray() + aValues.getLength();
805 0 : const PropertyValue* checkName = aValues.getConstArray();
806 0 : for ( ;checkName != valueEnd; ++checkName )
807 : {
808 0 : if ( checkName->Name.isEmpty() )
809 0 : throw IllegalArgumentException();
810 : }
811 :
812 0 : Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
813 0 : bModified = aSettings.getLength() != aValues.getLength();
814 0 : 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 0 : rConvertedValue = rValue;
829 0 : rOldValue <<= aSettings;
830 : }
831 0 : break;
832 : default:
833 : SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
834 : }
835 : }
836 0 : return bModified;
837 : }
838 :
839 : namespace
840 : {
841 : struct SelectPropertyName : public ::std::unary_function< PropertyValue, OUString >
842 : {
843 : public:
844 0 : const OUString& operator()( const PropertyValue& _lhs )
845 : {
846 0 : 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 0 : 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 0 : StringSet aToBeSetPropertyNames;
868 : ::std::transform(
869 : _rAllNewPropertyValues.getConstArray(),
870 0 : _rAllNewPropertyValues.getConstArray() + _rAllNewPropertyValues.getLength(),
871 : ::std::insert_iterator< StringSet >( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
872 : SelectPropertyName()
873 0 : );
874 :
875 : try
876 : {
877 : // obtain all properties currently known at the bag
878 0 : Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_QUERY_THROW );
879 0 : Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
880 :
881 0 : Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
882 :
883 : // loop through them, and reset resp. default properties which are not to be set
884 0 : const Property* pExistentProperty( aAllExistentProperties.getConstArray() );
885 0 : const Property* pExistentPropertyEnd( aAllExistentProperties.getConstArray() + aAllExistentProperties.getLength() );
886 0 : for ( ; pExistentProperty != pExistentPropertyEnd; ++pExistentProperty )
887 : {
888 0 : if ( aToBeSetPropertyNames.find( pExistentProperty->Name ) != aToBeSetPropertyNames.end() )
889 0 : 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 0 : if ( ( pExistentProperty->Attributes & PropertyAttribute::REMOVABLE ) != 0 )
894 0 : _rxPropertyBag->removeProperty( pExistentProperty->Name );
895 : else
896 0 : xPropertyState->setPropertyToDefault( pExistentProperty->Name );
897 : }
898 :
899 : // finally, set the new property values
900 0 : _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
901 : }
902 0 : catch( const Exception& )
903 : {
904 : DBG_UNHANDLED_EXCEPTION();
905 0 : }
906 0 : }
907 : }
908 :
909 0 : void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception, std::exception)
910 : {
911 : SAL_INFO("dbaccess", "ODatabaseSource::setFastPropertyValue_NoBroadcast" );
912 0 : if ( m_pImpl.is() )
913 : {
914 0 : switch(nHandle)
915 : {
916 : case PROPERTY_ID_TABLEFILTER:
917 0 : rValue >>= m_pImpl->m_aTableFilter;
918 0 : 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 0 : rValue >>= m_pImpl->m_sConnectURL;
938 0 : break;
939 : case PROPERTY_ID_INFO:
940 : {
941 0 : Sequence< PropertyValue > aInfo;
942 0 : OSL_VERIFY( rValue >>= aInfo );
943 0 : lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
944 : }
945 0 : break;
946 : case PROPERTY_ID_LAYOUTINFORMATION:
947 0 : rValue >>= m_pImpl->m_aLayoutInformation;
948 0 : break;
949 : }
950 0 : m_pImpl->setModified(sal_True);
951 : }
952 0 : }
953 :
954 0 : void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
955 : {
956 0 : if ( m_pImpl.is() )
957 : {
958 0 : switch (nHandle)
959 : {
960 : case PROPERTY_ID_TABLEFILTER:
961 0 : rValue <<= m_pImpl->m_aTableFilter;
962 0 : break;
963 : case PROPERTY_ID_TABLETYPEFILTER:
964 0 : rValue <<= m_pImpl->m_aTableTypeFilter;
965 0 : break;
966 : case PROPERTY_ID_USER:
967 0 : rValue <<= m_pImpl->m_sUser;
968 0 : break;
969 : case PROPERTY_ID_PASSWORD:
970 0 : rValue <<= m_pImpl->m_aPassword;
971 0 : break;
972 : case PROPERTY_ID_ISPASSWORDREQUIRED:
973 0 : rValue <<= m_pImpl->m_bPasswordRequired;
974 0 : break;
975 : case PROPERTY_ID_SUPPRESSVERSIONCL:
976 0 : rValue <<= m_pImpl->m_bSuppressVersionColumns;
977 0 : 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 0 : Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
987 0 : Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_QUERY_THROW );
988 0 : Sequence< Property > aSettings( xPST->getProperties() );
989 0 : ::std::map< OUString, sal_Int32 > aPropertyAttributes;
990 0 : for ( const Property* pSettings = aSettings.getConstArray();
991 0 : pSettings != aSettings.getConstArray() + aSettings.getLength();
992 : ++pSettings
993 : )
994 : {
995 0 : aPropertyAttributes[ pSettings->Name ] = pSettings->Attributes;
996 : }
997 :
998 : // get all current settings with their values
999 0 : Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
1000 :
1001 : // transform them so that only property values which fulfill certain
1002 : // criteria survive
1003 0 : Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
1004 : const PropertyValue* pCopyEnd = ::std::remove_copy_if(
1005 : aValues.getConstArray(),
1006 0 : aValues.getConstArray() + aValues.getLength(),
1007 : aNonDefaultOrUserDefined.getArray(),
1008 : IsDefaultAndNotRemoveable( aPropertyAttributes )
1009 0 : );
1010 0 : aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() );
1011 0 : rValue <<= aNonDefaultOrUserDefined;
1012 : }
1013 0 : catch( const Exception& )
1014 : {
1015 : DBG_UNHANDLED_EXCEPTION();
1016 : }
1017 : }
1018 0 : break;
1019 : case PROPERTY_ID_SETTINGS:
1020 0 : rValue <<= m_pImpl->m_xSettings;
1021 0 : break;
1022 : case PROPERTY_ID_URL:
1023 0 : rValue <<= m_pImpl->m_sConnectURL;
1024 0 : break;
1025 : case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
1026 0 : rValue <<= m_pImpl->getNumberFormatsSupplier();
1027 0 : break;
1028 : case PROPERTY_ID_NAME:
1029 0 : rValue <<= m_pImpl->m_sName;
1030 0 : break;
1031 : case PROPERTY_ID_LAYOUTINFORMATION:
1032 0 : rValue <<= m_pImpl->m_aLayoutInformation;
1033 0 : break;
1034 : default:
1035 : SAL_WARN("dbaccess","unknown Property");
1036 : }
1037 : }
1038 0 : }
1039 :
1040 : // XDataSource
1041 0 : void ODatabaseSource::setLoginTimeout(sal_Int32 seconds) throw( SQLException, RuntimeException, std::exception )
1042 : {
1043 : SAL_INFO("dbaccess", "ODatabaseSource::setLoginTimeout" );
1044 0 : ModelMethodGuard aGuard( *this );
1045 0 : m_pImpl->m_nLoginTimeout = seconds;
1046 0 : }
1047 :
1048 0 : sal_Int32 ODatabaseSource::getLoginTimeout(void) throw( SQLException, RuntimeException, std::exception )
1049 : {
1050 : SAL_INFO("dbaccess", "ODatabaseSource::getLoginTimeout" );
1051 0 : ModelMethodGuard aGuard( *this );
1052 0 : return m_pImpl->m_nLoginTimeout;
1053 : }
1054 :
1055 : // XCompletedConnection
1056 0 : Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
1057 : {
1058 : SAL_INFO("dbaccess", "ODatabaseSource::connectWithCompletion" );
1059 0 : return connectWithCompletion(_rxHandler,sal_False);
1060 : }
1061 :
1062 0 : Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password) throw( SQLException, RuntimeException, std::exception )
1063 : {
1064 : SAL_INFO("dbaccess", "ODatabaseSource::getConnection" );
1065 0 : return getConnection(user,password,sal_False);
1066 : }
1067 :
1068 0 : 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 0 : return getConnection(user,password,sal_True);
1072 : }
1073 :
1074 0 : Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
1075 : {
1076 : SAL_INFO("dbaccess", "ODatabaseSource::getIsolatedConnectionWithCompletion" );
1077 0 : return connectWithCompletion(_rxHandler,sal_True);
1078 : }
1079 :
1080 0 : Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,sal_Bool _bIsolated ) throw(SQLException, RuntimeException)
1081 : {
1082 : SAL_INFO("dbaccess", "ODatabaseSource::connectWithCompletion" );
1083 0 : ModelMethodGuard aGuard( *this );
1084 :
1085 0 : 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 0 : OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
1092 0 : sal_Bool bNewPasswordGiven = sal_False;
1093 :
1094 0 : 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 0 : 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 0 : }
1165 : }
1166 :
1167 0 : Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
1168 : {
1169 : SAL_INFO("dbaccess", "ODatabaseSource::buildIsolatedConnection" );
1170 0 : Reference< XConnection > xConn;
1171 0 : 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 0 : if ( xSdbcConn.is() )
1175 : {
1176 : // build a connection server and return it (no stubs)
1177 0 : xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
1178 : }
1179 0 : return xConn;
1180 : }
1181 :
1182 0 : Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,sal_Bool _bIsolated) throw( SQLException, RuntimeException )
1183 : {
1184 : SAL_INFO("dbaccess", "ODatabaseSource::getConnection" );
1185 0 : ModelMethodGuard aGuard( *this );
1186 :
1187 0 : Reference< XConnection > xConn;
1188 0 : if ( _bIsolated )
1189 : {
1190 0 : xConn = buildIsolatedConnection(user,password);
1191 : }
1192 : else
1193 : { // create a new proxy for the connection
1194 0 : if ( !m_pImpl->m_xSharedConnectionManager.is() )
1195 : {
1196 0 : m_pImpl->m_pSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext );
1197 0 : m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
1198 : }
1199 0 : xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
1200 0 : m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
1201 : }
1202 :
1203 0 : if ( xConn.is() )
1204 : {
1205 0 : Reference< XComponent> xComp(xConn,UNO_QUERY);
1206 0 : if ( xComp.is() )
1207 0 : xComp->addEventListener( static_cast< XContainerListener* >( this ) );
1208 0 : m_pImpl->m_aConnections.push_back(OWeakConnection(xConn));
1209 : }
1210 :
1211 0 : return xConn;
1212 : }
1213 :
1214 0 : Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( ) throw (RuntimeException, std::exception)
1215 : {
1216 : SAL_INFO("dbaccess", "ODatabaseSource::getBookmarks" );
1217 0 : ModelMethodGuard aGuard( *this );
1218 0 : return static_cast< XNameContainer* >(&m_aBookmarks);
1219 : }
1220 :
1221 0 : Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( ) throw(RuntimeException, std::exception)
1222 : {
1223 : SAL_INFO("dbaccess", "ODatabaseSource::getQueryDefinitions" );
1224 0 : ModelMethodGuard aGuard( *this );
1225 :
1226 0 : Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
1227 0 : if ( !xContainer.is() )
1228 : {
1229 0 : Any aValue;
1230 0 : ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xMy(*this);
1231 0 : if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
1232 : {
1233 0 : OUString sSupportService;
1234 0 : aValue >>= sSupportService;
1235 0 : 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 0 : }
1241 : }
1242 0 : if ( !xContainer.is() )
1243 : {
1244 0 : TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
1245 0 : xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, sal_False );
1246 : }
1247 0 : m_pImpl->m_xCommandDefinitions = xContainer;
1248 : }
1249 0 : return xContainer;
1250 : }
1251 :
1252 : // XTablesSupplier
1253 0 : Reference< XNameAccess > ODatabaseSource::getTables() throw( RuntimeException, std::exception )
1254 : {
1255 : SAL_INFO("dbaccess", "ODatabaseSource::getTables" );
1256 0 : ModelMethodGuard aGuard( *this );
1257 :
1258 0 : Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
1259 0 : if ( !xContainer.is() )
1260 : {
1261 0 : TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) );
1262 0 : xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, sal_True );
1263 0 : m_pImpl->m_xTableDefinitions = xContainer;
1264 : }
1265 0 : return xContainer;
1266 : }
1267 :
1268 0 : void SAL_CALL ODatabaseSource::flush( ) throw (RuntimeException, std::exception)
1269 : {
1270 : SAL_INFO("dbaccess", "ODatabaseSource::flush" );
1271 : try
1272 : {
1273 : // SYNCHRONIZED ->
1274 : {
1275 0 : ModelMethodGuard aGuard( *this );
1276 :
1277 : typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
1278 0 : SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
1279 :
1280 0 : if ( !xModel.is() )
1281 0 : xModel.reset( m_pImpl->createNewModel_deliverOwnership( false ), SharedModel::TakeOwnership );
1282 :
1283 0 : Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
1284 0 : xStorable->store();
1285 : }
1286 : // <- SYNCHRONIZED
1287 :
1288 0 : css::lang::EventObject aFlushedEvent(*this);
1289 0 : m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
1290 : }
1291 0 : catch( const Exception& )
1292 : {
1293 : DBG_UNHANDLED_EXCEPTION();
1294 : }
1295 0 : }
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 0 : 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 0 : m_aFlushListeners.addInterface(_xListener);
1334 0 : }
1335 :
1336 0 : 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 0 : m_aFlushListeners.removeInterface(_xListener);
1340 0 : }
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 0 : Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument() throw (RuntimeException, std::exception)
1368 : {
1369 : SAL_INFO("dbaccess", "ODatabaseSource::getDatabaseDocument" );
1370 0 : ModelMethodGuard aGuard( *this );
1371 :
1372 0 : Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
1373 0 : if ( !xModel.is() )
1374 0 : xModel = m_pImpl->createNewModel_deliverOwnership( false );
1375 :
1376 0 : 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: */
|