bump product version to 5.0.4.1
[LibreOffice.git] / extensions / source / abpilot / datasourcehandling.cxx
blob38952680239a9bf95a093f83ebd1dac5328c9062
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "abpresid.hrc"
22 #include "abptypes.hxx"
23 #include "componentmodule.hxx"
24 #include "datasourcehandling.hxx"
26 #include <boost/noncopyable.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <com/sun/star/container/XNameAccess.hpp>
29 #include <com/sun/star/frame/XStorable.hpp>
30 #include <com/sun/star/lang/XComponent.hpp>
31 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
32 #include <com/sun/star/sdb/DatabaseContext.hpp>
33 #include <com/sun/star/sdb/SQLContext.hpp>
34 #include <com/sun/star/sdb/XCompletedConnection.hpp>
35 #include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
36 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
37 #include <com/sun/star/sdbc/XConnection.hpp>
38 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
39 #include <com/sun/star/task/InteractionHandler.hpp>
40 #include <com/sun/star/uno/XNamingService.hpp>
42 #include <comphelper/interaction.hxx>
43 #include <comphelper/processfactory.hxx>
44 #include <tools/debug.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <unotools/confignode.hxx>
47 #include <unotools/sharedunocomponent.hxx>
48 #include <vcl/stdtext.hxx>
51 namespace abp
55 using namespace ::utl;
56 using namespace ::comphelper;
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::lang;
59 using namespace ::com::sun::star::sdb;
60 using namespace ::com::sun::star::sdbc;
61 using namespace ::com::sun::star::task;
62 using namespace ::com::sun::star::beans;
63 using namespace ::com::sun::star::sdbcx;
64 using namespace ::com::sun::star::container;
65 using namespace ::com::sun::star::frame;
68 struct PackageAccessControl { };
72 static Reference< XDatabaseContext > lcl_getDataSourceContext( const Reference< XComponentContext >& _rxContext )
74 Reference<XDatabaseContext> xContext = DatabaseContext::create(_rxContext);
75 return xContext;
79 /// creates a new data source and inserts it into the context
80 static void lcl_implCreateAndInsert(
81 const Reference< XComponentContext >& _rxContext, const OUString& _rName,
82 Reference< XPropertySet >& /* [out] */ _rxNewDataSource )
85 // get the data source context
86 Reference< XDatabaseContext > xContext = lcl_getDataSourceContext( _rxContext );
88 DBG_ASSERT( !xContext->hasByName( _rName ), "lcl_implCreateAndInsert: name already used!" );
89 (void)_rName;
92 // create a new data source
93 Reference< XPropertySet > xNewDataSource;
94 if (xContext.is())
95 xNewDataSource = Reference< XPropertySet >( xContext->createInstance(), UNO_QUERY );
96 DBG_ASSERT( xNewDataSource.is(), "lcl_implCreateAndInsert: could not create a new data source!" );
99 // insert the data source into the context
100 DBG_ASSERT( xContext.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" );
101 if (xContext.is())
103 // xDynamicContext->registerObject( _rName, xNewDataSource );
104 _rxNewDataSource = xNewDataSource;
109 /// creates and inserts a data source, and sets its URL property to the string given
110 static ODataSource lcl_implCreateAndSetURL(
111 const Reference< XComponentContext >& _rxORB, const OUString& _rName,
112 const sal_Char* _pInitialAsciiURL )
114 ODataSource aReturn( _rxORB );
117 // create the new data source
118 Reference< XPropertySet > xNewDataSource;
119 lcl_implCreateAndInsert( _rxORB, _rName, xNewDataSource );
122 // set the URL property
123 if (xNewDataSource.is())
125 xNewDataSource->setPropertyValue(
126 OUString( "URL" ),
127 makeAny( OUString::createFromAscii( _pInitialAsciiURL ) )
131 aReturn.setDataSource( xNewDataSource, _rName,PackageAccessControl() );
133 catch(const Exception&)
135 OSL_FAIL( "lcl_implCreateAndSetURL: caught an exception while creating the data source!" );
138 return aReturn;
141 void lcl_registerDataSource(
142 const Reference< XComponentContext >& _rxORB, const OUString& _sName,
143 const OUString& _sURL )
145 OSL_ENSURE( !_sName.isEmpty(), "lcl_registerDataSource: invalid name!" );
146 OSL_ENSURE( !_sURL.isEmpty(), "lcl_registerDataSource: invalid URL!" );
149 Reference< XDatabaseContext > xRegistrations( DatabaseContext::create(_rxORB) );
150 if ( xRegistrations->hasRegisteredDatabase( _sName ) )
151 xRegistrations->changeDatabaseLocation( _sName, _sURL );
152 else
153 xRegistrations->registerDatabaseLocation( _sName, _sURL );
155 catch( const Exception& )
157 DBG_UNHANDLED_EXCEPTION();
161 struct ODataSourceContextImpl: private boost::noncopyable
163 Reference< XComponentContext > xORB;
164 Reference< XNameAccess > xContext; /// the UNO data source context
165 StringBag aDataSourceNames; /// for quicker name checks (without the UNO overhead)
167 ODataSourceContextImpl( const Reference< XComponentContext >& _rxORB ) : xORB( _rxORB ) { }
170 ODataSourceContext::ODataSourceContext(const Reference< XComponentContext >& _rxORB)
171 :m_pImpl( new ODataSourceContextImpl( _rxORB ) )
175 // create the UNO context
176 m_pImpl->xContext = Reference<XNameAccess>(
177 lcl_getDataSourceContext( _rxORB ),
178 UNO_QUERY_THROW);
180 if (m_pImpl->xContext.is())
182 // collect the data source names
183 Sequence< OUString > aDSNames = m_pImpl->xContext->getElementNames();
184 const OUString* pDSNames = aDSNames.getConstArray();
185 const OUString* pDSNamesEnd = pDSNames + aDSNames.getLength();
187 for ( ;pDSNames != pDSNamesEnd; ++pDSNames )
188 m_pImpl->aDataSourceNames.insert( *pDSNames );
191 catch( const Exception& )
193 OSL_FAIL( "ODataSourceContext::ODataSourceContext: caught an exception!" );
196 ODataSourceContext::~ODataSourceContext()
198 delete(m_pImpl);
202 OUString& ODataSourceContext::disambiguate(OUString& _rDataSourceName)
204 OUString sCheck( _rDataSourceName );
205 StringBag::const_iterator aPos = m_pImpl->aDataSourceNames.find( sCheck );
207 sal_Int32 nPostfix = 1;
208 while ( ( m_pImpl->aDataSourceNames.end() != aPos ) && ( nPostfix < 65535 ) )
209 { // there already is a data source with this name
210 sCheck = _rDataSourceName;
211 sCheck += OUString::number( nPostfix++ );
213 aPos = m_pImpl->aDataSourceNames.find( sCheck );
216 _rDataSourceName = sCheck;
217 return _rDataSourceName;
221 void ODataSourceContext::getDataSourceNames( StringBag& _rNames ) const
223 _rNames = m_pImpl->aDataSourceNames;
227 ODataSource ODataSourceContext::createNewLDAP( const OUString& _rName)
229 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:ldap:" );
233 ODataSource ODataSourceContext::createNewMORK( const OUString& _rName)
235 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:mozilla" );
239 ODataSource ODataSourceContext::createNewThunderbird( const OUString& _rName )
241 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:thunderbird" );
245 ODataSource ODataSourceContext::createNewEvolutionLdap( const OUString& _rName)
247 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:ldap" );
250 ODataSource ODataSourceContext::createNewEvolutionGroupwise( const OUString& _rName)
252 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:groupwise" );
255 ODataSource ODataSourceContext::createNewEvolution( const OUString& _rName)
257 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:local" );
261 ODataSource ODataSourceContext::createNewKab( const OUString& _rName)
263 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:kab" );
267 ODataSource ODataSourceContext::createNewMacab( const OUString& _rName)
269 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:macab" );
273 ODataSource ODataSourceContext::createNewOutlook( const OUString& _rName)
275 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:outlook" );
279 ODataSource ODataSourceContext::createNewOE( const OUString& _rName)
281 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:outlookexp" );
285 ODataSource ODataSourceContext::createNewDBase( const OUString& _rName)
287 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:dbase:" );
290 struct ODataSourceImpl
292 public:
293 Reference< XComponentContext > xORB; /// the service factory
294 Reference< XPropertySet > xDataSource; /// the UNO data source
295 ::utl::SharedUNOComponent< XConnection >
296 xConnection;
297 StringBag aTables; // the cached table names
298 OUString sName;
299 bool bTablesUpToDate; // table name cache up-to-date?
301 ODataSourceImpl( const Reference< XComponentContext >& _rxORB )
302 :xORB( _rxORB )
303 ,bTablesUpToDate( false )
307 ODataSourceImpl( const ODataSourceImpl& _rSource );
311 ODataSourceImpl::ODataSourceImpl( const ODataSourceImpl& _rSource )
312 :xORB( _rSource.xORB )
313 ,xDataSource( _rSource.xDataSource )
314 ,xConnection( _rSource.xConnection )
315 ,aTables( _rSource.aTables )
316 ,sName( _rSource.sName )
317 ,bTablesUpToDate( _rSource.bTablesUpToDate )
321 ODataSource::ODataSource( const ODataSource& _rSource )
322 :m_pImpl( NULL )
324 *this = _rSource;
328 ODataSource& ODataSource::operator=( const ODataSource& _rSource )
330 if( this != &_rSource )
332 delete m_pImpl;
333 m_pImpl = new ODataSourceImpl( *_rSource.m_pImpl );
335 return *this;
339 ODataSource::ODataSource( const Reference< XComponentContext >& _rxORB )
340 :m_pImpl(new ODataSourceImpl(_rxORB))
345 ODataSource::~ODataSource( )
347 delete m_pImpl;
351 void ODataSource::store()
353 if (!isValid())
354 // nothing to do
355 return;
358 Reference< XDocumentDataSource > xDocAccess( m_pImpl->xDataSource, UNO_QUERY );
359 Reference< XStorable > xStorable;
360 if ( xDocAccess.is() )
361 xStorable.set(xDocAccess->getDatabaseDocument(), css::uno::UNO_QUERY);
362 OSL_ENSURE( xStorable.is(),"DataSource is no XStorable!" );
363 if ( xStorable.is() )
364 xStorable->storeAsURL(m_pImpl->sName,Sequence<PropertyValue>());
366 catch(const Exception&)
368 OSL_FAIL( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
372 void ODataSource::registerDataSource( const OUString& _sRegisteredDataSourceName)
374 if (!isValid())
375 // nothing to do
376 return;
380 // invalidate ourself
381 lcl_registerDataSource(m_pImpl->xORB,_sRegisteredDataSourceName,m_pImpl->sName);
383 catch(const Exception&)
385 OSL_FAIL( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
390 void ODataSource::setDataSource( const Reference< XPropertySet >& _rxDS,const OUString& _sName, PackageAccessControl )
392 if (m_pImpl->xDataSource.get() == _rxDS.get())
393 // nothing to do
394 return;
396 if ( isConnected() )
397 disconnect();
399 m_pImpl->sName = _sName;
400 m_pImpl->xDataSource = _rxDS;
404 void ODataSource::remove()
406 if (!isValid())
407 // nothing to do
408 return;
412 // invalidate ourself
413 m_pImpl->xDataSource.clear();
415 catch(const Exception&)
417 OSL_FAIL( "ODataSource::remove: caught an exception while creating the data source!" );
422 bool ODataSource::rename( const OUString& _rName )
424 if (!isValid())
425 // nothing to do
426 return false;
428 m_pImpl->sName = _rName;
429 return true;
433 OUString ODataSource::getName() const
435 if ( !isValid() )
436 return OUString();
437 return m_pImpl->sName;
441 bool ODataSource::hasTable( const OUString& _rTableName ) const
443 if ( !isConnected() )
444 return false;
446 const StringBag& aTables( getTableNames() );
447 return aTables.find( _rTableName ) != aTables.end();
451 const StringBag& ODataSource::getTableNames() const
453 m_pImpl->aTables.clear();
454 if ( !isConnected() )
456 OSL_FAIL( "ODataSource::getTableNames: not connected!" );
458 else
462 // get the tables container from the connection
463 Reference< XTablesSupplier > xSuppTables( m_pImpl->xConnection.getTyped(), UNO_QUERY );
464 Reference< XNameAccess > xTables;
465 if ( xSuppTables.is( ) )
466 xTables = xSuppTables->getTables();
467 DBG_ASSERT( xTables.is(), "ODataSource::getTableNames: could not retrieve the tables container!" );
469 // get the names
470 Sequence< OUString > aTableNames;
471 if ( xTables.is( ) )
472 aTableNames = xTables->getElementNames( );
474 // copy the names
475 const OUString* pTableNames = aTableNames.getConstArray();
476 const OUString* pTableNamesEnd = pTableNames + aTableNames.getLength();
477 for (;pTableNames < pTableNamesEnd; ++pTableNames)
478 m_pImpl->aTables.insert( *pTableNames );
480 catch(const Exception&)
485 // now the table cache is up-to-date
486 m_pImpl->bTablesUpToDate = true;
487 return m_pImpl->aTables;
491 bool ODataSource::connect( vcl::Window* _pMessageParent )
493 if ( isConnected( ) )
494 // nothing to do
495 return true;
498 // create the interaction handler (needed for authentication and error handling)
499 Reference< XInteractionHandler > xInteractions;
502 xInteractions.set(
503 InteractionHandler::createWithParent(m_pImpl->xORB, 0),
504 UNO_QUERY);
506 catch(const Exception&)
511 // failure to create the interaction handler is a serious issue ...
512 if (!xInteractions.is())
514 OUString s_sInteractionHandlerServiceName("com.sun.star.task.InteractionHandler");
515 if ( _pMessageParent )
516 ShowServiceNotAvailableError( _pMessageParent, s_sInteractionHandlerServiceName, true );
517 return false;
521 // open the connection
522 Any aError;
523 Reference< XConnection > xConnection;
526 Reference< XCompletedConnection > xComplConn( m_pImpl->xDataSource, UNO_QUERY );
527 DBG_ASSERT( xComplConn.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" );
528 if ( xComplConn.is() )
529 xConnection = xComplConn->connectWithCompletion( xInteractions );
531 catch( const SQLContext& e ) { aError <<= e; }
532 catch( const SQLWarning& e ) { aError <<= e; }
533 catch( const SQLException& e ) { aError <<= e; }
534 catch( const Exception& )
536 OSL_FAIL( "ODataSource::connect: caught a generic exception!" );
540 // handle errors
541 if ( aError.hasValue() && _pMessageParent )
545 SQLException aException;
546 aError >>= aException;
547 if ( aException.Message.isEmpty() )
549 // prepend some context info
550 SQLContext aDetailedError;
551 aDetailedError.Message = ModuleRes(RID_STR_NOCONNECTION).toString();
552 aDetailedError.Details = ModuleRes(RID_STR_PLEASECHECKSETTINGS).toString();
553 aDetailedError.NextException = aError;
554 // handle (aka display) the new context info
555 xInteractions->handle( new OInteractionRequest( makeAny( aDetailedError ) ) );
557 else
559 // handle (aka display) the original error
560 xInteractions->handle( new OInteractionRequest( makeAny( aException ) ) );
563 catch( const Exception& )
565 OSL_FAIL( "ODataSource::connect: caught an exception while trying to display the error!" );
569 if ( !xConnection.is() )
570 return false;
573 // success
574 m_pImpl->xConnection.reset( xConnection );
575 m_pImpl->aTables.clear();
576 m_pImpl->bTablesUpToDate = false;
578 return true;
582 void ODataSource::disconnect( )
584 m_pImpl->xConnection.clear();
585 m_pImpl->aTables.clear();
586 m_pImpl->bTablesUpToDate = false;
590 bool ODataSource::isConnected( ) const
592 return m_pImpl->xConnection.is();
596 bool ODataSource::isValid() const
598 return m_pImpl && m_pImpl->xDataSource.is();
601 Reference< XPropertySet > ODataSource::getDataSource() const
603 return m_pImpl ? m_pImpl->xDataSource : Reference< XPropertySet >();
607 } // namespace abp
610 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */