1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_dbaccess.hxx"
26
27 #include "apitools.hxx"
28 #include "core_resource.hrc"
29 #include "core_resource.hxx"
30 #include "databasecontext.hxx"
31 #include "databasedocument.hxx"
32 #include "databaseregistrations.hxx"
33 #include "datasource.hxx"
34 #include "dbastrings.hrc"
35 #include "module_dba.hxx"
36
37 /** === being UNO includes === **/
38 #include <com/sun/star/beans/NamedValue.hpp>
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/document/MacroExecMode.hpp>
42 #include <com/sun/star/document/XFilter.hpp>
43 #include <com/sun/star/document/XImporter.hpp>
44 #include <com/sun/star/frame/XDesktop.hpp>
45 #include <com/sun/star/frame/XModel.hpp>
46 #include <com/sun/star/frame/XModel2.hpp>
47 #include <com/sun/star/frame/XTerminateListener.hpp>
48 #include <com/sun/star/lang/DisposedException.hpp>
49 #include <com/sun/star/registry/InvalidRegistryException.hpp>
50 #include <com/sun/star/sdbc/XDataSource.hpp>
51 #include <com/sun/star/task/InteractionClassification.hpp>
52 #include <com/sun/star/ucb/InteractiveIOException.hpp>
53 #include <com/sun/star/ucb/IOErrorCode.hpp>
54 #include <com/sun/star/util/XCloseable.hpp>
55 /** === end UNO includes === **/
56
57 #include <basic/basmgr.hxx>
58 #include <comphelper/enumhelper.hxx>
59 #include <comphelper/evtlistenerhlp.hxx>
60 #include <comphelper/namedvaluecollection.hxx>
61 #include <comphelper/processfactory.hxx>
62 #include <comphelper/sequence.hxx>
63 #include <cppuhelper/implbase1.hxx>
64 #include <cppuhelper/typeprovider.hxx>
65 #include <cppuhelper/exc_hlp.hxx>
66 #include <svl/filenotation.hxx>
67 #include <tools/debug.hxx>
68 #include <tools/diagnose_ex.h>
69 #include <tools/fsys.hxx>
70 #include <tools/urlobj.hxx>
71 #include <ucbhelper/content.hxx>
72 #include <unotools/confignode.hxx>
73 #include <unotools/pathoptions.hxx>
74 #include <unotools/sharedunocomponent.hxx>
75 #include <list>
76 #include <boost/bind.hpp>
77
78 using namespace ::com::sun::star::sdbc;
79 using namespace ::com::sun::star::sdb;
80 using namespace ::com::sun::star::beans;
81 using namespace ::com::sun::star::uno;
82 using namespace ::com::sun::star::document;
83 using namespace ::com::sun::star::frame;
84 using namespace ::com::sun::star::lang;
85 using namespace ::com::sun::star::container;
86 using namespace ::com::sun::star::util;
87 using namespace ::com::sun::star::registry;
88 using namespace ::com::sun::star;
89 using namespace ::cppu;
90 using namespace ::osl;
91 using namespace ::utl;
92
93 using ::com::sun::star::task::InteractionClassification_ERROR;
94 using ::com::sun::star::ucb::IOErrorCode_NO_FILE;
95 using ::com::sun::star::ucb::InteractiveIOException;
96 using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING;
97 using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING_PATH;
98
99 //==========================================================================
100
createRegistryInfo_ODatabaseContext()101 extern "C" void SAL_CALL createRegistryInfo_ODatabaseContext()
102 {
103 static ::dba::OLegacySingletonRegistration< ::dbaccess::ODatabaseContext > aODatabaseContext_AutoRegistration;
104 }
105
106 //........................................................................
107 namespace dbaccess
108 {
109 //........................................................................
110
111 // .............................................................................
112 typedef ::cppu::WeakImplHelper1 < XTerminateListener
113 > DatabaseDocumentLoader_Base;
114 class DatabaseDocumentLoader : public DatabaseDocumentLoader_Base
115 {
116 private:
117 Reference< XDesktop > m_xDesktop;
118 ::std::list< const ODatabaseModelImpl* > m_aDatabaseDocuments;
119
120 public:
121 DatabaseDocumentLoader( const comphelper::ComponentContext& _aContext);
122
append(const ODatabaseModelImpl & _rModelImpl)123 inline void append(const ODatabaseModelImpl& _rModelImpl )
124 {
125 m_aDatabaseDocuments.push_back(&_rModelImpl);
126 }
remove(const ODatabaseModelImpl & _rModelImpl)127 inline void remove(const ODatabaseModelImpl& _rModelImpl) { m_aDatabaseDocuments.remove(&_rModelImpl); }
128
129 private:
130 // XTerminateListener
131 virtual void SAL_CALL queryTermination( const lang::EventObject& Event );
132 virtual void SAL_CALL notifyTermination( const lang::EventObject& Event );
133 // XEventListener
134 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source );
135 };
136
137 // .............................................................................
DatabaseDocumentLoader(const comphelper::ComponentContext & _aContext)138 DatabaseDocumentLoader::DatabaseDocumentLoader( const comphelper::ComponentContext& _aContext )
139 {
140 acquire();
141 try
142 {
143 m_xDesktop.set( _aContext.createComponent( (rtl::OUString)SERVICE_FRAME_DESKTOP ), UNO_QUERY_THROW );
144 m_xDesktop->addTerminateListener( this );
145 }
146 catch( const Exception& )
147 {
148 DBG_UNHANDLED_EXCEPTION();
149 }
150 }
151
152 struct TerminateFunctor : ::std::unary_function<ODatabaseModelImpl* , void>
153 {
operator ()dbaccess::TerminateFunctor154 void operator()( const ODatabaseModelImpl* _pModelImpl ) const
155 {
156 try
157 {
158 const Reference< XModel2> xModel( _pModelImpl ->getModel_noCreate(),UNO_QUERY_THROW );
159 if ( !xModel->getControllers()->hasMoreElements() )
160 {
161 Reference<util::XCloseable> xCloseable(xModel,UNO_QUERY_THROW);
162 xCloseable->close(sal_False);
163 } // if ( !xModel->getControllers()->hasMoreElements() )
164 }
165 catch(const CloseVetoException&)
166 {
167 throw TerminationVetoException();
168 }
169 }
170 };
171 // .............................................................................
queryTermination(const lang::EventObject &)172 void SAL_CALL DatabaseDocumentLoader::queryTermination( const lang::EventObject& /*Event*/ )
173 {
174 ::std::list< const ODatabaseModelImpl* > aCopy(m_aDatabaseDocuments);
175 ::std::for_each(aCopy.begin(),aCopy.end(),TerminateFunctor());
176 }
177
178 // .............................................................................
notifyTermination(const lang::EventObject &)179 void SAL_CALL DatabaseDocumentLoader::notifyTermination( const lang::EventObject& /*Event*/ )
180 {
181 }
182 // .............................................................................
disposing(const lang::EventObject &)183 void SAL_CALL DatabaseDocumentLoader::disposing( const lang::EventObject& /*Source*/ )
184 {
185 }
186
187 //= ODatabaseContext
188 //==========================================================================
189 //--------------------------------------------------------------------------
ODatabaseContext(const Reference<XComponentContext> & _rxContext)190 ODatabaseContext::ODatabaseContext( const Reference< XComponentContext >& _rxContext )
191 :DatabaseAccessContext_Base(m_aMutex)
192 ,m_aContext( _rxContext )
193 ,m_aContainerListeners(m_aMutex)
194 {
195 m_pDatabaseDocumentLoader = new DatabaseDocumentLoader( m_aContext );
196 ::basic::BasicManagerRepository::registerCreationListener( *this );
197
198 osl_incrementInterlockedCount( &m_refCount );
199 {
200 m_xDBRegistrationAggregate.set( createDataSourceRegistrations( m_aContext ), UNO_SET_THROW );
201 m_xDatabaseRegistrations.set( m_xDBRegistrationAggregate, UNO_QUERY_THROW );
202
203 m_xDBRegistrationAggregate->setDelegator( *this );
204 }
205 osl_decrementInterlockedCount( &m_refCount );
206 }
207
208 //--------------------------------------------------------------------------
~ODatabaseContext()209 ODatabaseContext::~ODatabaseContext()
210 {
211 ::basic::BasicManagerRepository::revokeCreationListener( *this );
212 if ( m_pDatabaseDocumentLoader )
213 m_pDatabaseDocumentLoader->release();
214
215 m_xDBRegistrationAggregate->setDelegator( NULL );
216 m_xDBRegistrationAggregate.clear();
217 m_xDatabaseRegistrations.clear();
218 }
219
220 // Helper
221 //------------------------------------------------------------------------------
getImplementationName_static()222 rtl::OUString ODatabaseContext::getImplementationName_static()
223
224 {
225 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.dba.ODatabaseContext"));
226 }
227
228 //------------------------------------------------------------------------------
Create(const Reference<XComponentContext> & _rxContext)229 Reference< XInterface > ODatabaseContext::Create(const Reference< XComponentContext >& _rxContext)
230 {
231 return *( new ODatabaseContext( _rxContext ) );
232 }
233
234 //------------------------------------------------------------------------------
getSupportedServiceNames_static(void)235 Sequence< rtl::OUString > ODatabaseContext::getSupportedServiceNames_static(void)
236 {
237 Sequence< ::rtl::OUString > aSNS( 1 );
238 aSNS[0] = SERVICE_SDB_DATABASECONTEXT;
239 return aSNS;
240 }
241
242 // XServiceInfo
243 //------------------------------------------------------------------------------
getImplementationName()244 rtl::OUString ODatabaseContext::getImplementationName( )
245 {
246 return getImplementationName_static();
247 }
248
249 //------------------------------------------------------------------------------
supportsService(const::rtl::OUString & _rServiceName)250 sal_Bool ODatabaseContext::supportsService( const ::rtl::OUString& _rServiceName )
251 {
252 return ::comphelper::findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0;
253 }
254
255 //------------------------------------------------------------------------------
getSupportedServiceNames()256 Sequence< ::rtl::OUString > ODatabaseContext::getSupportedServiceNames( )
257 {
258 return getSupportedServiceNames_static();
259 }
260
261 //--------------------------------------------------------------------------
impl_createNewDataSource()262 Reference< XInterface > ODatabaseContext::impl_createNewDataSource()
263 {
264 ::rtl::Reference<ODatabaseModelImpl> pImpl( new ODatabaseModelImpl( m_aContext.getLegacyServiceFactory(), *this ) );
265 Reference< XDataSource > xDataSource( pImpl->getOrCreateDataSource() );
266
267 return xDataSource.get();
268 }
269
270 //--------------------------------------------------------------------------
createInstance()271 Reference< XInterface > SAL_CALL ODatabaseContext::createInstance( )
272 {
273 // for convenience of the API user, we ensure the document is fully initialized (effectively: XLoadable::initNew
274 // has been called at the DatabaseDocument).
275 return impl_createNewDataSource();
276 }
277
278 //--------------------------------------------------------------------------
createInstanceWithArguments(const Sequence<Any> & _rArguments)279 Reference< XInterface > SAL_CALL ODatabaseContext::createInstanceWithArguments( const Sequence< Any >& _rArguments )
280 {
281 ::comphelper::NamedValueCollection aArgs( _rArguments );
282 ::rtl::OUString sURL = aArgs.getOrDefault( (::rtl::OUString)INFO_POOLURL, ::rtl::OUString() );
283
284 Reference< XInterface > xDataSource;
285 if ( sURL.getLength() )
286 xDataSource = getObject( sURL );
287
288 if ( !xDataSource.is() )
289 xDataSource = impl_createNewDataSource();
290
291 return xDataSource;
292 }
293 // DatabaseAccessContext_Base
294 //------------------------------------------------------------------------------
disposing()295 void ODatabaseContext::disposing()
296 {
297 // notify our listener
298 com::sun::star::lang::EventObject aDisposeEvent(static_cast< XContainer* >(this));
299 m_aContainerListeners.disposeAndClear(aDisposeEvent);
300
301 // dispose the data sources
302 ObjectCache::iterator aEnd = m_aDatabaseObjects.end();
303 for ( ObjectCache::iterator aIter = m_aDatabaseObjects.begin();
304 aIter != aEnd;
305 ++aIter
306 )
307 {
308 aIter->second->dispose();
309 }
310 m_aDatabaseObjects.clear();
311 }
312
313 // XNamingService
314 //------------------------------------------------------------------------------
getRegisteredObject(const rtl::OUString & _rName)315 Reference< XInterface > ODatabaseContext::getRegisteredObject(const rtl::OUString& _rName)
316 {
317 MutexGuard aGuard(m_aMutex);
318 ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
319
320 ::rtl::OUString sURL( getDatabaseLocation( _rName ) );
321
322 if ( !sURL.getLength() )
323 // there is a registration for this name, but no URL
324 throw IllegalArgumentException();
325
326 // check if URL is already loaded
327 Reference< XInterface > xExistent = getObject( sURL );
328 if ( xExistent.is() )
329 return xExistent;
330
331 return loadObjectFromURL( _rName, sURL );
332 }
333 // -----------------------------------------------------------------------------
loadObjectFromURL(const::rtl::OUString & _rName,const::rtl::OUString & _sURL)334 Reference< XInterface > ODatabaseContext::loadObjectFromURL(const ::rtl::OUString& _rName,const ::rtl::OUString& _sURL)
335 {
336 INetURLObject aURL( _sURL );
337 if ( aURL.GetProtocol() == INET_PROT_NOT_VALID )
338 throw NoSuchElementException( _rName, *this );
339
340 try
341 {
342 ::ucbhelper::Content aContent( _sURL, NULL );
343 if ( !aContent.isDocument() )
344 throw InteractiveIOException(
345 _sURL, *this, InteractionClassification_ERROR, IOErrorCode_NO_FILE
346 );
347 }
348 catch ( const InteractiveIOException& e )
349 {
350 if ( ( e.Code == IOErrorCode_NO_FILE )
351 || ( e.Code == IOErrorCode_NOT_EXISTING )
352 || ( e.Code == IOErrorCode_NOT_EXISTING_PATH )
353 )
354 {
355 // #i40463# #i39187#
356 String sErrorMessage( DBACORE_RESSTRING( RID_STR_FILE_DOES_NOT_EXIST ) );
357 ::svt::OFileNotation aTransformer( _sURL );
358 sErrorMessage.SearchAndReplaceAscii( "$file$", aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) );
359
360 SQLException aError;
361 aError.Message = sErrorMessage;
362
363 throw WrappedTargetException( _sURL, *this, makeAny( aError ) );
364 }
365 throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() );
366 }
367 catch( const Exception& )
368 {
369 throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() );
370 }
371
372 OSL_ENSURE( m_aDatabaseObjects.find( _sURL ) == m_aDatabaseObjects.end(),
373 "ODatabaseContext::loadObjectFromURL: not intended for already-cached objects!" );
374
375 ::rtl::Reference< ODatabaseModelImpl > pModelImpl;
376 {
377 pModelImpl.set( new ODatabaseModelImpl( _rName, m_aContext.getLegacyServiceFactory(), *this ) );
378
379 Reference< XModel > xModel( pModelImpl->createNewModel_deliverOwnership( false ), UNO_SET_THROW );
380 Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
381
382 ::comphelper::NamedValueCollection aArgs;
383 aArgs.put( "URL", _sURL );
384 aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
385 aArgs.put( "InteractionHandler", m_aContext.createComponent( "com.sun.star.task.InteractionHandler" ) );
386
387 Sequence< PropertyValue > aResource( aArgs.getPropertyValues() );
388 xLoad->load( aResource );
389 xModel->attachResource( _sURL, aResource );
390
391 ::utl::CloseableComponent aEnsureClose( xModel );
392 }
393
394 setTransientProperties( _sURL, *pModelImpl );
395
396 return pModelImpl->getOrCreateDataSource().get();
397 }
398 // -----------------------------------------------------------------------------
appendAtTerminateListener(const ODatabaseModelImpl & _rDataSourceModel)399 void ODatabaseContext::appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel)
400 {
401 m_pDatabaseDocumentLoader->append(_rDataSourceModel);
402 }
403 // -----------------------------------------------------------------------------
removeFromTerminateListener(const ODatabaseModelImpl & _rDataSourceModel)404 void ODatabaseContext::removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel)
405 {
406 m_pDatabaseDocumentLoader->remove(_rDataSourceModel);
407 }
408 // -----------------------------------------------------------------------------
setTransientProperties(const::rtl::OUString & _sURL,ODatabaseModelImpl & _rDataSourceModel)409 void ODatabaseContext::setTransientProperties(const ::rtl::OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel )
410 {
411 if ( m_aDatasourceProperties.end() == m_aDatasourceProperties.find(_sURL) )
412 return;
413 try
414 {
415 ::rtl::OUString sAuthFailedPassword;
416 Reference< XPropertySet > xDSProps( _rDataSourceModel.getOrCreateDataSource(), UNO_QUERY_THROW );
417 const Sequence< PropertyValue >& rSessionPersistentProps = m_aDatasourceProperties[_sURL];
418 const PropertyValue* pProp = rSessionPersistentProps.getConstArray();
419 const PropertyValue* pPropsEnd = rSessionPersistentProps.getConstArray() + rSessionPersistentProps.getLength();
420 for ( ; pProp != pPropsEnd; ++pProp )
421 {
422 if ( pProp->Name.equalsAscii( "AuthFailedPassword" ) )
423 {
424 OSL_VERIFY( pProp->Value >>= sAuthFailedPassword );
425 }
426 else
427 {
428 xDSProps->setPropertyValue( pProp->Name, pProp->Value );
429 }
430 }
431
432 _rDataSourceModel.m_sFailedPassword = sAuthFailedPassword;
433 }
434 catch( const Exception& )
435 {
436 DBG_UNHANDLED_EXCEPTION();
437 }
438 }
439
440 //------------------------------------------------------------------------------
registerObject(const rtl::OUString & _rName,const Reference<XInterface> & _rxObject)441 void ODatabaseContext::registerObject(const rtl::OUString& _rName, const Reference< XInterface > & _rxObject)
442 {
443 MutexGuard aGuard(m_aMutex);
444 ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
445
446 if ( !_rName.getLength() )
447 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
448
449 Reference< XDocumentDataSource > xDocDataSource( _rxObject, UNO_QUERY );
450 Reference< XModel > xModel( xDocDataSource.is() ? xDocDataSource->getDatabaseDocument() : Reference< XOfficeDatabaseDocument >(), UNO_QUERY );
451 if ( !xModel.is() )
452 throw IllegalArgumentException( ::rtl::OUString(), *this, 2 );
453
454 ::rtl::OUString sURL = xModel->getURL();
455 if ( !sURL.getLength() )
456 throw IllegalArgumentException( DBACORE_RESSTRING( RID_STR_DATASOURCE_NOT_STORED ), *this, 2 );
457
458 registerDatabaseLocation( _rName, sURL );
459
460 ODatabaseSource::setName( xDocDataSource, _rName, ODatabaseSource::DBContextAccess() );
461
462 // notify our container listeners
463 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_rName), makeAny(_rxObject), Any());
464 m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
465 }
466
467 //------------------------------------------------------------------------------
storeTransientProperties(ODatabaseModelImpl & _rModelImpl)468 void ODatabaseContext::storeTransientProperties( ODatabaseModelImpl& _rModelImpl)
469 {
470 Reference< XPropertySet > xSource( _rModelImpl.getOrCreateDataSource(), UNO_QUERY );
471 ::comphelper::NamedValueCollection aRememberProps;
472
473 try
474 {
475 // get the info about the properties, check which ones are transient and not readonly
476 Reference< XPropertySetInfo > xSetInfo;
477 if (xSource.is())
478 xSetInfo = xSource->getPropertySetInfo();
479 Sequence< Property > aProperties;
480 if (xSetInfo.is())
481 aProperties = xSetInfo->getProperties();
482
483 if (aProperties.getLength())
484 {
485 const Property* pProperties = aProperties.getConstArray();
486 for ( sal_Int32 i=0; i<aProperties.getLength(); ++i, ++pProperties )
487 {
488 if ( ( ( pProperties->Attributes & PropertyAttribute::TRANSIENT) != 0 )
489 && ( ( pProperties->Attributes & PropertyAttribute::READONLY) == 0 )
490 )
491 {
492 // found such a property
493 aRememberProps.put( pProperties->Name, xSource->getPropertyValue( pProperties->Name ) );
494 }
495 }
496 }
497 }
498 catch ( const Exception& )
499 {
500 DBG_UNHANDLED_EXCEPTION();
501 }
502
503 // additionally, remember the "failed password", which is not available as property
504 // #i86178# / 2008-02-19 / frank.schoenheit@sun.com
505 aRememberProps.put( "AuthFailedPassword", _rModelImpl.m_sFailedPassword );
506
507 ::rtl::OUString sDocumentURL( _rModelImpl.getURL() );
508 if ( m_aDatabaseObjects.find( sDocumentURL ) != m_aDatabaseObjects.end() )
509 {
510 m_aDatasourceProperties[ sDocumentURL ] = aRememberProps.getPropertyValues();
511 }
512 else if ( m_aDatabaseObjects.find( _rModelImpl.m_sName ) != m_aDatabaseObjects.end() )
513 {
514 OSL_ENSURE( false, "ODatabaseContext::storeTransientProperties: a database document register by name? This shouldn't happen anymore!" );
515 // all the code should have been changed so that registration is by URL only
516 m_aDatasourceProperties[ _rModelImpl.m_sName ] = aRememberProps.getPropertyValues();
517 }
518 else
519 {
520 OSL_ENSURE( ( sDocumentURL.getLength() == 0 ) && ( _rModelImpl.m_sName.getLength() == 0 ),
521 "ODatabaseContext::storeTransientProperties: a non-empty data source which I do not know?!" );
522 }
523 }
524
525 //------------------------------------------------------------------------------
addContainerListener(const Reference<XContainerListener> & _rxListener)526 void SAL_CALL ODatabaseContext::addContainerListener( const Reference< XContainerListener >& _rxListener )
527 {
528 m_aContainerListeners.addInterface(_rxListener);
529 }
530
531 //------------------------------------------------------------------------------
removeContainerListener(const Reference<XContainerListener> & _rxListener)532 void SAL_CALL ODatabaseContext::removeContainerListener( const Reference< XContainerListener >& _rxListener )
533 {
534 m_aContainerListeners.removeInterface(_rxListener);
535 }
536
537 //------------------------------------------------------------------------------
revokeObject(const rtl::OUString & _rName)538 void ODatabaseContext::revokeObject(const rtl::OUString& _rName)
539 {
540 ClearableMutexGuard aGuard(m_aMutex);
541 ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
542
543 ::rtl::OUString sURL = getDatabaseLocation( _rName );
544
545 revokeDatabaseLocation( _rName );
546 // will throw if something goes wrong
547
548 if ( m_aDatabaseObjects.find( _rName ) != m_aDatabaseObjects.end() )
549 {
550 m_aDatasourceProperties[ sURL ] = m_aDatasourceProperties[ _rName ];
551 }
552
553 // check if URL is already loaded
554 ObjectCacheIterator aExistent = m_aDatabaseObjects.find( sURL );
555 if ( aExistent != m_aDatabaseObjects.end() )
556 m_aDatabaseObjects.erase( aExistent );
557
558 // notify our container listeners
559 ContainerEvent aEvent( *this, makeAny( _rName ), Any(), Any() );
560 aGuard.clear();
561 m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
562 }
563
564 //------------------------------------------------------------------------------
hasRegisteredDatabase(const::rtl::OUString & _Name)565 ::sal_Bool SAL_CALL ODatabaseContext::hasRegisteredDatabase( const ::rtl::OUString& _Name )
566 {
567 return m_xDatabaseRegistrations->hasRegisteredDatabase( _Name );
568 }
569
570 //------------------------------------------------------------------------------
getRegistrationNames()571 Sequence< ::rtl::OUString > SAL_CALL ODatabaseContext::getRegistrationNames()
572 {
573 return m_xDatabaseRegistrations->getRegistrationNames();
574 }
575
576 //------------------------------------------------------------------------------
getDatabaseLocation(const::rtl::OUString & _Name)577 ::rtl::OUString SAL_CALL ODatabaseContext::getDatabaseLocation( const ::rtl::OUString& _Name )
578 {
579 return m_xDatabaseRegistrations->getDatabaseLocation( _Name );
580 }
581
582 //------------------------------------------------------------------------------
registerDatabaseLocation(const::rtl::OUString & _Name,const::rtl::OUString & _Location)583 void SAL_CALL ODatabaseContext::registerDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _Location )
584 {
585 m_xDatabaseRegistrations->registerDatabaseLocation( _Name, _Location );
586 }
587
588 //------------------------------------------------------------------------------
revokeDatabaseLocation(const::rtl::OUString & _Name)589 void SAL_CALL ODatabaseContext::revokeDatabaseLocation( const ::rtl::OUString& _Name )
590 {
591 m_xDatabaseRegistrations->revokeDatabaseLocation( _Name );
592 }
593
594 //------------------------------------------------------------------------------
changeDatabaseLocation(const::rtl::OUString & _Name,const::rtl::OUString & _NewLocation)595 void SAL_CALL ODatabaseContext::changeDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _NewLocation )
596 {
597 m_xDatabaseRegistrations->changeDatabaseLocation( _Name, _NewLocation );
598 }
599
600 //------------------------------------------------------------------------------
isDatabaseRegistrationReadOnly(const::rtl::OUString & _Name)601 ::sal_Bool SAL_CALL ODatabaseContext::isDatabaseRegistrationReadOnly( const ::rtl::OUString& _Name )
602 {
603 return m_xDatabaseRegistrations->isDatabaseRegistrationReadOnly( _Name );
604 }
605
606 //------------------------------------------------------------------------------
addDatabaseRegistrationsListener(const Reference<XDatabaseRegistrationsListener> & _Listener)607 void SAL_CALL ODatabaseContext::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener )
608 {
609 m_xDatabaseRegistrations->addDatabaseRegistrationsListener( _Listener );
610 }
611
612 //------------------------------------------------------------------------------
removeDatabaseRegistrationsListener(const Reference<XDatabaseRegistrationsListener> & _Listener)613 void SAL_CALL ODatabaseContext::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener )
614 {
615 m_xDatabaseRegistrations->removeDatabaseRegistrationsListener( _Listener );
616 }
617
618 // ::com::sun::star::container::XElementAccess
619 //------------------------------------------------------------------------------
getElementType()620 Type ODatabaseContext::getElementType( )
621 {
622 return::getCppuType(static_cast<Reference<XDataSource>*>(NULL));
623 }
624
625 //------------------------------------------------------------------------------
hasElements(void)626 sal_Bool ODatabaseContext::hasElements(void)
627 {
628 MutexGuard aGuard(m_aMutex);
629 ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
630
631 return 0 != getElementNames().getLength();
632 }
633
634 // ::com::sun::star::container::XEnumerationAccess
635 //------------------------------------------------------------------------------
createEnumeration(void)636 Reference< ::com::sun::star::container::XEnumeration > ODatabaseContext::createEnumeration(void)
637 {
638 MutexGuard aGuard(m_aMutex);
639 return new ::comphelper::OEnumerationByName(static_cast<XNameAccess*>(this));
640 }
641
642 // ::com::sun::star::container::XNameAccess
643 //------------------------------------------------------------------------------
getByName(const rtl::OUString & _rName)644 Any ODatabaseContext::getByName(const rtl::OUString& _rName)
645 {
646 MutexGuard aGuard(m_aMutex);
647 ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
648 if ( !_rName.getLength() )
649 throw NoSuchElementException(_rName, *this);
650
651 try
652 {
653 Reference< XInterface > xExistent = getObject( _rName );
654 if ( xExistent.is() )
655 return makeAny( xExistent );
656
657 // see whether this is an registered name
658 ::rtl::OUString sURL;
659 if ( hasRegisteredDatabase( _rName ) )
660 {
661 sURL = getDatabaseLocation( _rName );
662 // is the object cached under its URL?
663 xExistent = getObject( sURL );
664 }
665 else
666 // interpret the name as URL
667 sURL = _rName;
668
669 if ( !xExistent.is() )
670 // try to load this as URL
671 xExistent = loadObjectFromURL( _rName, sURL );
672 return makeAny( xExistent );
673 }
674 catch (NoSuchElementException&)
675 { // let these exceptions through
676 throw;
677 }
678 catch (WrappedTargetException&)
679 { // let these exceptions through
680 throw;
681 }
682 catch (RuntimeException&)
683 { // let these exceptions through
684 throw;
685 }
686 catch (Exception& e)
687 { // exceptions other than the specified ones -> wrap
688 Any aError = ::cppu::getCaughtException();
689 throw WrappedTargetException(_rName, *this, aError );
690 }
691 }
692
693 //------------------------------------------------------------------------------
getElementNames(void)694 Sequence< rtl::OUString > ODatabaseContext::getElementNames(void)
695 {
696 MutexGuard aGuard(m_aMutex);
697 ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
698
699 return getRegistrationNames();
700 }
701
702 //------------------------------------------------------------------------------
hasByName(const rtl::OUString & _rName)703 sal_Bool ODatabaseContext::hasByName(const rtl::OUString& _rName)
704 {
705 MutexGuard aGuard(m_aMutex);
706 ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
707
708 return hasRegisteredDatabase( _rName );
709 }
710
711 // -----------------------------------------------------------------------------
getObject(const::rtl::OUString & _rURL)712 Reference< XInterface > ODatabaseContext::getObject( const ::rtl::OUString& _rURL )
713 {
714 ObjectCacheIterator aFind = m_aDatabaseObjects.find( _rURL );
715 Reference< XInterface > xExistent;
716 if ( aFind != m_aDatabaseObjects.end() )
717 xExistent = aFind->second->getOrCreateDataSource();
718 return xExistent;
719 }
720 // -----------------------------------------------------------------------------
registerDatabaseDocument(ODatabaseModelImpl & _rModelImpl)721 void ODatabaseContext::registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl )
722 {
723 ::rtl::OUString sURL( _rModelImpl.getURL() );
724 #if OSL_DEBUG_LEVEL > 1
725 OSL_TRACE( "DatabaseContext: registering %s", ::rtl::OUStringToOString( sURL, RTL_TEXTENCODING_UTF8 ).getStr() );
726 #endif
727 if ( m_aDatabaseObjects.find( sURL ) == m_aDatabaseObjects.end() )
728 {
729 m_aDatabaseObjects[ sURL ] = &_rModelImpl;
730 setTransientProperties( sURL, _rModelImpl );
731 }
732 else
733 OSL_ENSURE( false, "ODatabaseContext::registerDatabaseDocument: already have an object registered for this URL!" );
734 }
735 // -----------------------------------------------------------------------------
revokeDatabaseDocument(const ODatabaseModelImpl & _rModelImpl)736 void ODatabaseContext::revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl )
737 {
738 ::rtl::OUString sURL( _rModelImpl.getURL() );
739 #if OSL_DEBUG_LEVEL > 1
740 OSL_TRACE( "DatabaseContext: deregistering %s", ::rtl::OUStringToOString( sURL, RTL_TEXTENCODING_UTF8 ).getStr() );
741 #endif
742 m_aDatabaseObjects.erase( sURL );
743 }
744 // -----------------------------------------------------------------------------
databaseDocumentURLChange(const::rtl::OUString & _rOldURL,const::rtl::OUString & _rNewURL)745 void ODatabaseContext::databaseDocumentURLChange( const ::rtl::OUString& _rOldURL, const ::rtl::OUString& _rNewURL )
746 {
747 #if OSL_DEBUG_LEVEL > 1
748 OSL_TRACE( "DatabaseContext: changing registration from %s to %s",
749 ::rtl::OUStringToOString( _rOldURL, RTL_TEXTENCODING_UTF8 ).getStr(),
750 ::rtl::OUStringToOString( _rNewURL, RTL_TEXTENCODING_UTF8 ).getStr() );
751 #endif
752 ObjectCache::iterator oldPos = m_aDatabaseObjects.find( _rOldURL );
753 ENSURE_OR_THROW( oldPos != m_aDatabaseObjects.end(), "illegal old database document URL" );
754 ObjectCache::iterator newPos = m_aDatabaseObjects.find( _rNewURL );
755 ENSURE_OR_THROW( newPos == m_aDatabaseObjects.end(), "illegal new database document URL" );
756
757 m_aDatabaseObjects[ _rNewURL ] = oldPos->second;
758 m_aDatabaseObjects.erase( oldPos );
759 }
760 // -----------------------------------------------------------------------------
getSomething(const Sequence<sal_Int8> & rId)761 sal_Int64 SAL_CALL ODatabaseContext::getSomething( const Sequence< sal_Int8 >& rId )
762 {
763 if (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) )
764 return reinterpret_cast<sal_Int64>(this);
765
766 return 0;
767 }
768 // -----------------------------------------------------------------------------
getUnoTunnelImplementationId()769 Sequence< sal_Int8 > ODatabaseContext::getUnoTunnelImplementationId()
770 {
771 static ::cppu::OImplementationId * pId = 0;
772 if (! pId)
773 {
774 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
775 if (! pId)
776 {
777 static ::cppu::OImplementationId aId;
778 pId = &aId;
779 }
780 }
781 return pId->getImplementationId();
782 }
783
784 // -----------------------------------------------------------------------------
onBasicManagerCreated(const Reference<XModel> & _rxForDocument,BasicManager & _rBasicManager)785 void ODatabaseContext::onBasicManagerCreated( const Reference< XModel >& _rxForDocument, BasicManager& _rBasicManager )
786 {
787 // if it's a database document ...
788 Reference< XOfficeDatabaseDocument > xDatabaseDocument( _rxForDocument, UNO_QUERY );
789 // ... or a sub document of a database document ...
790 if ( !xDatabaseDocument.is() )
791 {
792 Reference< XChild > xDocAsChild( _rxForDocument, UNO_QUERY );
793 if ( xDocAsChild.is() )
794 xDatabaseDocument.set( xDocAsChild->getParent(), UNO_QUERY );
795 }
796
797 // ... whose BasicManager has just been created, then add the global DatabaseDocument variable to its scope.
798 if ( xDatabaseDocument.is() )
799 _rBasicManager.SetGlobalUNOConstant( "ThisDatabaseDocument", makeAny( xDatabaseDocument ) );
800 }
801
802 //........................................................................
803 } // namespace dbaccess
804 //........................................................................
805