1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
);
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!" );
92 // create a new data source
93 Reference
< XPropertySet
> xNewDataSource
;
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)!" );
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(
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!" );
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
);
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
),
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()
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
293 Reference
< XComponentContext
> xORB
; /// the service factory
294 Reference
< XPropertySet
> xDataSource
; /// the UNO data source
295 ::utl::SharedUNOComponent
< XConnection
>
297 StringBag aTables
; // the cached table names
299 bool bTablesUpToDate
; // table name cache up-to-date?
301 ODataSourceImpl( const Reference
< XComponentContext
>& _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
)
328 ODataSource
& ODataSource::operator=( const ODataSource
& _rSource
)
330 if( this != &_rSource
)
333 m_pImpl
= new ODataSourceImpl( *_rSource
.m_pImpl
);
339 ODataSource::ODataSource( const Reference
< XComponentContext
>& _rxORB
)
340 :m_pImpl(new ODataSourceImpl(_rxORB
))
345 ODataSource::~ODataSource( )
351 void ODataSource::store()
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
)
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())
399 m_pImpl
->sName
= _sName
;
400 m_pImpl
->xDataSource
= _rxDS
;
404 void ODataSource::remove()
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
)
428 m_pImpl
->sName
= _rName
;
433 OUString
ODataSource::getName() const
437 return m_pImpl
->sName
;
441 bool ODataSource::hasTable( const OUString
& _rTableName
) const
443 if ( !isConnected() )
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!" );
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!" );
470 Sequence
< OUString
> aTableNames
;
472 aTableNames
= xTables
->getElementNames( );
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( ) )
498 // create the interaction handler (needed for authentication and error handling)
499 Reference
< XInteractionHandler
> xInteractions
;
503 InteractionHandler::createWithParent(m_pImpl
->xORB
, 0),
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 );
521 // open the connection
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!" );
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
) ) );
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() )
574 m_pImpl
->xConnection
.reset( xConnection
);
575 m_pImpl
->aTables
.clear();
576 m_pImpl
->bTablesUpToDate
= false;
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
>();
610 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */