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 <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/container/XNameAccess.hpp>
28 #include <com/sun/star/frame/XStorable.hpp>
29 #include <com/sun/star/lang/XComponent.hpp>
30 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
31 #include <com/sun/star/sdb/DatabaseContext.hpp>
32 #include <com/sun/star/sdb/SQLContext.hpp>
33 #include <com/sun/star/sdb/XCompletedConnection.hpp>
34 #include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
35 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
36 #include <com/sun/star/sdbc/XConnection.hpp>
37 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
38 #include <com/sun/star/task/InteractionHandler.hpp>
39 #include <com/sun/star/uno/XNamingService.hpp>
41 #include <comphelper/interaction.hxx>
42 #include <comphelper/processfactory.hxx>
43 #include <tools/debug.hxx>
44 #include <tools/diagnose_ex.h>
45 #include <unotools/confignode.hxx>
46 #include <unotools/sharedunocomponent.hxx>
47 #include <vcl/stdtext.hxx>
49 //.........................................................................
52 //.........................................................................
54 using namespace ::utl
;
55 using namespace ::comphelper
;
56 using namespace ::com::sun::star::uno
;
57 using namespace ::com::sun::star::lang
;
58 using namespace ::com::sun::star::sdb
;
59 using namespace ::com::sun::star::sdbc
;
60 using namespace ::com::sun::star::task
;
61 using namespace ::com::sun::star::beans
;
62 using namespace ::com::sun::star::sdbcx
;
63 using namespace ::com::sun::star::container
;
64 using namespace ::com::sun::star::frame
;
66 //=====================================================================
67 struct PackageAccessControl
{ };
69 //=====================================================================
70 //---------------------------------------------------------------------
71 static Reference
< XDatabaseContext
> lcl_getDataSourceContext( const Reference
< XComponentContext
>& _rxContext
) SAL_THROW (( Exception
))
73 Reference
<XDatabaseContext
> xContext
= DatabaseContext::create(_rxContext
);
77 //---------------------------------------------------------------------
78 /// creates a new data source and inserts it into the context
79 static void lcl_implCreateAndInsert(
80 const Reference
< XComponentContext
>& _rxContext
, const OUString
& _rName
,
81 Reference
< XPropertySet
>& /* [out] */ _rxNewDataSource
) SAL_THROW (( ::com::sun::star::uno::Exception
))
83 //.............................................................
84 // get the data source context
85 Reference
< XDatabaseContext
> xContext
= lcl_getDataSourceContext( _rxContext
);
87 DBG_ASSERT( !xContext
->hasByName( _rName
), "lcl_implCreateAndInsert: name already used!" );
90 //.............................................................
91 // create a new data source
92 Reference
< XSingleServiceFactory
> xFactory( xContext
, UNO_QUERY
);
93 Reference
< XPropertySet
> xNewDataSource
;
95 xNewDataSource
= Reference
< XPropertySet
>( xFactory
->createInstance(), UNO_QUERY
);
96 DBG_ASSERT( xNewDataSource
.is(), "lcl_implCreateAndInsert: could not create a new data source!" );
98 //.............................................................
99 // insert the data source into the context
100 Reference
< XNamingService
> xDynamicContext( xContext
, UNO_QUERY
);
101 DBG_ASSERT( xDynamicContext
.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" );
102 if (xDynamicContext
.is())
104 // xDynamicContext->registerObject( _rName, xNewDataSource );
105 _rxNewDataSource
= xNewDataSource
;
109 //---------------------------------------------------------------------
110 /// creates and inserts a data source, and sets it's URL property to the string given
111 static ODataSource
lcl_implCreateAndSetURL(
112 const Reference
< XComponentContext
>& _rxORB
, const OUString
& _rName
,
113 const sal_Char
* _pInitialAsciiURL
) SAL_THROW (( ))
115 ODataSource
aReturn( _rxORB
);
118 // create the new data source
119 Reference
< XPropertySet
> xNewDataSource
;
120 lcl_implCreateAndInsert( _rxORB
, _rName
, xNewDataSource
);
122 //.............................................................
123 // set the URL property
124 if (xNewDataSource
.is())
126 xNewDataSource
->setPropertyValue(
128 makeAny( OUString::createFromAscii( _pInitialAsciiURL
) )
132 aReturn
.setDataSource( xNewDataSource
, _rName
,PackageAccessControl() );
134 catch(const Exception
&)
136 OSL_FAIL( "lcl_implCreateAndSetURL: caught an exception while creating the data source!" );
141 //---------------------------------------------------------------------
142 void lcl_registerDataSource(
143 const Reference
< XComponentContext
>& _rxORB
, const OUString
& _sName
,
144 const OUString
& _sURL
) SAL_THROW (( ::com::sun::star::uno::Exception
))
146 OSL_ENSURE( !_sName
.isEmpty(), "lcl_registerDataSource: invalid name!" );
147 OSL_ENSURE( !_sURL
.isEmpty(), "lcl_registerDataSource: invalid URL!" );
150 Reference
< XDatabaseContext
> xRegistrations( DatabaseContext::create(_rxORB
) );
151 if ( xRegistrations
->hasRegisteredDatabase( _sName
) )
152 xRegistrations
->changeDatabaseLocation( _sName
, _sURL
);
154 xRegistrations
->registerDatabaseLocation( _sName
, _sURL
);
156 catch( const Exception
& )
158 DBG_UNHANDLED_EXCEPTION();
162 //=====================================================================
163 //= ODataSourceContextImpl
164 //=====================================================================
165 struct ODataSourceContextImpl
167 Reference
< XComponentContext
> xORB
;
168 Reference
< XNameAccess
> xContext
; /// the UNO data source context
169 StringBag aDataSourceNames
; /// for quicker name checks (without the UNO overhead)
171 ODataSourceContextImpl( const Reference
< XComponentContext
>& _rxORB
) : xORB( _rxORB
) { }
172 ODataSourceContextImpl( const ODataSourceContextImpl
& _rSource
)
173 :xORB ( _rSource
.xORB
)
174 ,xContext ( _rSource
.xContext
)
179 //=====================================================================
180 //= ODataSourceContext
181 //=====================================================================
182 //---------------------------------------------------------------------
183 ODataSourceContext::ODataSourceContext(const Reference
< XComponentContext
>& _rxORB
)
184 :m_pImpl( new ODataSourceContextImpl( _rxORB
) )
188 // create the UNO context
189 m_pImpl
->xContext
= Reference
<XNameAccess
>(
190 lcl_getDataSourceContext( _rxORB
),
193 if (m_pImpl
->xContext
.is())
195 // collect the data source names
196 Sequence
< OUString
> aDSNames
= m_pImpl
->xContext
->getElementNames();
197 const OUString
* pDSNames
= aDSNames
.getConstArray();
198 const OUString
* pDSNamesEnd
= pDSNames
+ aDSNames
.getLength();
200 for ( ;pDSNames
!= pDSNamesEnd
; ++pDSNames
)
201 m_pImpl
->aDataSourceNames
.insert( *pDSNames
);
204 catch( const Exception
& )
206 OSL_FAIL( "ODataSourceContext::ODataSourceContext: caught an exception!" );
209 ODataSourceContext::~ODataSourceContext()
214 //---------------------------------------------------------------------
215 OUString
& ODataSourceContext::disambiguate(OUString
& _rDataSourceName
)
217 OUString
sCheck( _rDataSourceName
);
218 ConstStringBagIterator aPos
= m_pImpl
->aDataSourceNames
.find( sCheck
);
220 sal_Int32 nPostFix
= 1;
221 while ( ( m_pImpl
->aDataSourceNames
.end() != aPos
) && ( nPostFix
< 65535 ) )
222 { // there already is a data source with this name
223 sCheck
= _rDataSourceName
;
224 sCheck
+= OUString::valueOf( nPostFix
++ );
226 aPos
= m_pImpl
->aDataSourceNames
.find( sCheck
);
229 _rDataSourceName
= sCheck
;
230 return _rDataSourceName
;
233 //---------------------------------------------------------------------
234 void ODataSourceContext::getDataSourceNames( StringBag
& _rNames
) const SAL_THROW (( ))
236 _rNames
= m_pImpl
->aDataSourceNames
;
239 //---------------------------------------------------------------------
240 ODataSource
ODataSourceContext::createNewLDAP( const OUString
& _rName
) SAL_THROW (( ))
242 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:ldap:" );
245 //---------------------------------------------------------------------
246 ODataSource
ODataSourceContext::createNewMORK( const OUString
& _rName
) SAL_THROW (( ))
248 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:mozilla" );
251 //---------------------------------------------------------------------
252 ODataSource
ODataSourceContext::createNewThunderbird( const OUString
& _rName
) SAL_THROW (( ))
254 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:thunderbird" );
257 //---------------------------------------------------------------------
258 ODataSource
ODataSourceContext::createNewEvolutionLdap( const OUString
& _rName
) SAL_THROW (( ))
260 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:ldap" );
262 //---------------------------------------------------------------------
263 ODataSource
ODataSourceContext::createNewEvolutionGroupwise( const OUString
& _rName
) SAL_THROW (( ))
265 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:groupwise" );
267 //---------------------------------------------------------------------
268 ODataSource
ODataSourceContext::createNewEvolution( const OUString
& _rName
) SAL_THROW (( ))
270 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:local" );
273 //---------------------------------------------------------------------
274 ODataSource
ODataSourceContext::createNewKab( const OUString
& _rName
) SAL_THROW (( ))
276 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:kab" );
279 //---------------------------------------------------------------------
280 ODataSource
ODataSourceContext::createNewMacab( const OUString
& _rName
) SAL_THROW (( ))
282 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:macab" );
285 //---------------------------------------------------------------------
286 ODataSource
ODataSourceContext::createNewOutlook( const OUString
& _rName
) SAL_THROW (( ))
288 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:outlook" );
291 //---------------------------------------------------------------------
292 ODataSource
ODataSourceContext::createNewOE( const OUString
& _rName
) SAL_THROW (( ))
294 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:outlookexp" );
297 //---------------------------------------------------------------------
298 ODataSource
ODataSourceContext::createNewDBase( const OUString
& _rName
) SAL_THROW (( ))
300 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:dbase:" );
303 //=====================================================================
305 //=====================================================================
306 struct ODataSourceImpl
309 Reference
< XComponentContext
> xORB
; /// the service factory
310 Reference
< XPropertySet
> xDataSource
; /// the UNO data source
311 ::utl::SharedUNOComponent
< XConnection
>
313 StringBag aTables
; // the cached table names
315 sal_Bool bTablesUpToDate
; // table name cache up-to-date?
317 ODataSourceImpl( const Reference
< XComponentContext
>& _rxORB
)
319 ,bTablesUpToDate( sal_False
)
323 ODataSourceImpl( const ODataSourceImpl
& _rSource
);
326 //---------------------------------------------------------------------
327 ODataSourceImpl::ODataSourceImpl( const ODataSourceImpl
& _rSource
)
328 :xORB( _rSource
.xORB
)
329 ,xDataSource( _rSource
.xDataSource
)
330 ,xConnection( _rSource
.xConnection
)
331 ,aTables( _rSource
.aTables
)
332 ,sName( _rSource
.sName
)
333 ,bTablesUpToDate( _rSource
.bTablesUpToDate
)
337 //=====================================================================
339 //=====================================================================
340 //---------------------------------------------------------------------
341 ODataSource::ODataSource( const ODataSource
& _rSource
)
347 //---------------------------------------------------------------------
348 ODataSource
& ODataSource::operator=( const ODataSource
& _rSource
)
350 if( this != &_rSource
)
353 m_pImpl
= new ODataSourceImpl( *_rSource
.m_pImpl
);
358 //---------------------------------------------------------------------
359 ODataSource::ODataSource( const Reference
< XComponentContext
>& _rxORB
)
360 :m_pImpl(new ODataSourceImpl(_rxORB
))
364 //---------------------------------------------------------------------
365 ODataSource::~ODataSource( )
370 //---------------------------------------------------------------------
371 void ODataSource::store() SAL_THROW (( ))
378 Reference
< XDocumentDataSource
> xDocAccess( m_pImpl
->xDataSource
, UNO_QUERY
);
379 Reference
< XStorable
> xStorable
;
380 if ( xDocAccess
.is() )
381 xStorable
= xStorable
.query( xDocAccess
->getDatabaseDocument() );
382 OSL_ENSURE( xStorable
.is(),"DataSource is no XStorable!" );
383 if ( xStorable
.is() )
384 xStorable
->storeAsURL(m_pImpl
->sName
,Sequence
<PropertyValue
>());
386 catch(const Exception
&)
388 OSL_FAIL( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
391 //---------------------------------------------------------------------
392 void ODataSource::registerDataSource( const OUString
& _sRegisteredDataSourceName
) SAL_THROW (( ))
400 // invalidate ourself
401 lcl_registerDataSource(m_pImpl
->xORB
,_sRegisteredDataSourceName
,m_pImpl
->sName
);
403 catch(const Exception
&)
405 OSL_FAIL( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
409 //---------------------------------------------------------------------
410 void ODataSource::setDataSource( const Reference
< XPropertySet
>& _rxDS
,const OUString
& _sName
, PackageAccessControl
)
412 if (m_pImpl
->xDataSource
.get() == _rxDS
.get())
419 m_pImpl
->sName
= _sName
;
420 m_pImpl
->xDataSource
= _rxDS
;
423 //---------------------------------------------------------------------
424 void ODataSource::remove() SAL_THROW (( ))
432 // invalidate ourself
433 m_pImpl
->xDataSource
.clear();
435 catch(const Exception
&)
437 OSL_FAIL( "ODataSource::remove: caught an exception while creating the data source!" );
441 //---------------------------------------------------------------------
442 sal_Bool
ODataSource::rename( const OUString
& _rName
) SAL_THROW (( ))
448 m_pImpl
->sName
= _rName
;
452 //---------------------------------------------------------------------
453 OUString
ODataSource::getName() const SAL_THROW (( ))
457 return m_pImpl
->sName
;
460 //---------------------------------------------------------------------
461 bool ODataSource::hasTable( const OUString
& _rTableName
) const
463 if ( !isConnected() )
466 const StringBag
& aTables( getTableNames() );
467 return aTables
.find( _rTableName
) != aTables
.end();
470 //---------------------------------------------------------------------
471 const StringBag
& ODataSource::getTableNames() const SAL_THROW (( ))
473 m_pImpl
->aTables
.clear();
474 if ( !isConnected() )
476 OSL_FAIL( "ODataSource::getTableNames: not connected!" );
482 // get the tables container from the connection
483 Reference
< XTablesSupplier
> xSuppTables( m_pImpl
->xConnection
.getTyped(), UNO_QUERY
);
484 Reference
< XNameAccess
> xTables
;
485 if ( xSuppTables
.is( ) )
486 xTables
= xSuppTables
->getTables();
487 DBG_ASSERT( xTables
.is(), "ODataSource::getTableNames: could not retrieve the tables container!" );
490 Sequence
< OUString
> aTableNames
;
492 aTableNames
= xTables
->getElementNames( );
495 const OUString
* pTableNames
= aTableNames
.getConstArray();
496 const OUString
* pTableNamesEnd
= pTableNames
+ aTableNames
.getLength();
497 for (;pTableNames
< pTableNamesEnd
; ++pTableNames
)
498 m_pImpl
->aTables
.insert( *pTableNames
);
500 catch(const Exception
&)
505 // now the table cache is up-to-date
506 m_pImpl
->bTablesUpToDate
= sal_True
;
507 return m_pImpl
->aTables
;
510 //---------------------------------------------------------------------
511 sal_Bool
ODataSource::connect( Window
* _pMessageParent
) SAL_THROW (( ))
513 if ( isConnected( ) )
517 // ................................................................
518 // create the interaction handler (needed for authentication and error handling)
519 Reference
< XInteractionHandler
> xInteractions
;
523 InteractionHandler::createWithParent(m_pImpl
->xORB
, 0),
526 catch(const Exception
&)
530 // ................................................................
531 // failure to create the interaction handler is a serious issue ...
532 if (!xInteractions
.is())
534 OUString
s_sInteractionHandlerServiceName("com.sun.star.task.InteractionHandler");
535 if ( _pMessageParent
)
536 ShowServiceNotAvailableError( _pMessageParent
, s_sInteractionHandlerServiceName
, sal_True
);
540 // ................................................................
541 // open the connection
543 Reference
< XConnection
> xConnection
;
546 Reference
< XCompletedConnection
> xComplConn( m_pImpl
->xDataSource
, UNO_QUERY
);
547 DBG_ASSERT( xComplConn
.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" );
548 if ( xComplConn
.is() )
549 xConnection
= xComplConn
->connectWithCompletion( xInteractions
);
551 catch( const SQLContext
& e
) { aError
<<= e
; }
552 catch( const SQLWarning
& e
) { aError
<<= e
; }
553 catch( const SQLException
& e
) { aError
<<= e
; }
554 catch( const Exception
& )
556 OSL_FAIL( "ODataSource::connect: caught a generic exception!" );
559 // ................................................................
561 if ( aError
.hasValue() && _pMessageParent
)
565 SQLException aException
;
566 aError
>>= aException
;
567 if ( aException
.Message
.isEmpty() )
569 // prepend some context info
570 SQLContext aDetailedError
;
571 aDetailedError
.Message
= String( ModuleRes( RID_STR_NOCONNECTION
) );
572 aDetailedError
.Details
= String( ModuleRes( RID_STR_PLEASECHECKSETTINGS
) );
573 aDetailedError
.NextException
= aError
;
574 // handle (aka display) the new context info
575 xInteractions
->handle( new OInteractionRequest( makeAny( aDetailedError
) ) );
579 // handle (aka display) the original error
580 xInteractions
->handle( new OInteractionRequest( makeAny( aException
) ) );
583 catch( const Exception
& )
585 OSL_FAIL( "ODataSource::connect: caught an exception while trying to display the error!" );
589 if ( !xConnection
.is() )
592 // ................................................................
594 m_pImpl
->xConnection
.reset( xConnection
);
595 m_pImpl
->aTables
.clear();
596 m_pImpl
->bTablesUpToDate
= sal_False
;
601 //---------------------------------------------------------------------
602 void ODataSource::disconnect( ) SAL_THROW (( ))
604 m_pImpl
->xConnection
.clear();
605 m_pImpl
->aTables
.clear();
606 m_pImpl
->bTablesUpToDate
= sal_False
;
609 //---------------------------------------------------------------------
610 sal_Bool
ODataSource::isConnected( ) const SAL_THROW (( ))
612 return m_pImpl
->xConnection
.is();
615 //---------------------------------------------------------------------
616 sal_Bool
ODataSource::isValid() const SAL_THROW (( ))
618 return m_pImpl
&& m_pImpl
->xDataSource
.is();
620 //---------------------------------------------------------------------
621 Reference
< XPropertySet
> ODataSource::getDataSource() const SAL_THROW (( ))
623 return m_pImpl
? m_pImpl
->xDataSource
: Reference
< XPropertySet
>();
626 //.........................................................................
628 //.........................................................................
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */