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 :
21 : #include "abpresid.hrc"
22 : #include "abptypes.hxx"
23 : #include "componentmodule.hxx"
24 : #include "datasourcehandling.hxx"
25 :
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>
40 :
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>
48 :
49 :
50 : namespace abp
51 : {
52 :
53 :
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;
65 :
66 :
67 : struct PackageAccessControl { };
68 :
69 :
70 :
71 0 : static Reference< XDatabaseContext > lcl_getDataSourceContext( const Reference< XComponentContext >& _rxContext ) SAL_THROW (( Exception ))
72 : {
73 0 : Reference<XDatabaseContext> xContext = DatabaseContext::create(_rxContext);
74 0 : return xContext;
75 : }
76 :
77 :
78 : /// creates a new data source and inserts it into the context
79 0 : static void lcl_implCreateAndInsert(
80 : const Reference< XComponentContext >& _rxContext, const OUString& _rName,
81 : Reference< XPropertySet >& /* [out] */ _rxNewDataSource ) SAL_THROW (( ::com::sun::star::uno::Exception ))
82 : {
83 :
84 : // get the data source context
85 0 : Reference< XDatabaseContext > xContext = lcl_getDataSourceContext( _rxContext );
86 :
87 : DBG_ASSERT( !xContext->hasByName( _rName ), "lcl_implCreateAndInsert: name already used!" );
88 : (void)_rName;
89 :
90 :
91 : // create a new data source
92 0 : Reference< XPropertySet > xNewDataSource;
93 0 : if (xContext.is())
94 0 : xNewDataSource = Reference< XPropertySet >( xContext->createInstance(), UNO_QUERY );
95 : DBG_ASSERT( xNewDataSource.is(), "lcl_implCreateAndInsert: could not create a new data source!" );
96 :
97 :
98 : // insert the data source into the context
99 : DBG_ASSERT( xContext.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" );
100 0 : if (xContext.is())
101 : {
102 : // xDynamicContext->registerObject( _rName, xNewDataSource );
103 0 : _rxNewDataSource = xNewDataSource;
104 0 : }
105 0 : }
106 :
107 :
108 : /// creates and inserts a data source, and sets its URL property to the string given
109 0 : static ODataSource lcl_implCreateAndSetURL(
110 : const Reference< XComponentContext >& _rxORB, const OUString& _rName,
111 : const sal_Char* _pInitialAsciiURL ) SAL_THROW (( ))
112 : {
113 0 : ODataSource aReturn( _rxORB );
114 : try
115 : {
116 : // create the new data source
117 0 : Reference< XPropertySet > xNewDataSource;
118 0 : lcl_implCreateAndInsert( _rxORB, _rName, xNewDataSource );
119 :
120 :
121 : // set the URL property
122 0 : if (xNewDataSource.is())
123 : {
124 0 : xNewDataSource->setPropertyValue(
125 : OUString( "URL" ),
126 : makeAny( OUString::createFromAscii( _pInitialAsciiURL ) )
127 0 : );
128 : }
129 :
130 0 : aReturn.setDataSource( xNewDataSource, _rName,PackageAccessControl() );
131 : }
132 0 : catch(const Exception&)
133 : {
134 : OSL_FAIL( "lcl_implCreateAndSetURL: caught an exception while creating the data source!" );
135 : }
136 :
137 0 : return aReturn;
138 : }
139 :
140 0 : void lcl_registerDataSource(
141 : const Reference< XComponentContext >& _rxORB, const OUString& _sName,
142 : const OUString& _sURL ) SAL_THROW (( ::com::sun::star::uno::Exception ))
143 : {
144 : OSL_ENSURE( !_sName.isEmpty(), "lcl_registerDataSource: invalid name!" );
145 : OSL_ENSURE( !_sURL.isEmpty(), "lcl_registerDataSource: invalid URL!" );
146 : try
147 : {
148 0 : Reference< XDatabaseContext > xRegistrations( DatabaseContext::create(_rxORB) );
149 0 : if ( xRegistrations->hasRegisteredDatabase( _sName ) )
150 0 : xRegistrations->changeDatabaseLocation( _sName, _sURL );
151 : else
152 0 : xRegistrations->registerDatabaseLocation( _sName, _sURL );
153 : }
154 0 : catch( const Exception& )
155 : {
156 : DBG_UNHANDLED_EXCEPTION();
157 : }
158 0 : }
159 :
160 :
161 : //= ODataSourceContextImpl
162 :
163 0 : struct ODataSourceContextImpl
164 : {
165 : Reference< XComponentContext > xORB;
166 : Reference< XNameAccess > xContext; /// the UNO data source context
167 : StringBag aDataSourceNames; /// for quicker name checks (without the UNO overhead)
168 :
169 0 : ODataSourceContextImpl( const Reference< XComponentContext >& _rxORB ) : xORB( _rxORB ) { }
170 : ODataSourceContextImpl( const ODataSourceContextImpl& _rSource )
171 : :xORB ( _rSource.xORB )
172 : ,xContext ( _rSource.xContext )
173 : {
174 : }
175 : };
176 :
177 :
178 : //= ODataSourceContext
179 :
180 :
181 0 : ODataSourceContext::ODataSourceContext(const Reference< XComponentContext >& _rxORB)
182 0 : :m_pImpl( new ODataSourceContextImpl( _rxORB ) )
183 : {
184 : try
185 : {
186 : // create the UNO context
187 0 : m_pImpl->xContext = Reference<XNameAccess>(
188 : lcl_getDataSourceContext( _rxORB ),
189 0 : UNO_QUERY_THROW);
190 :
191 0 : if (m_pImpl->xContext.is())
192 : {
193 : // collect the data source names
194 0 : Sequence< OUString > aDSNames = m_pImpl->xContext->getElementNames();
195 0 : const OUString* pDSNames = aDSNames.getConstArray();
196 0 : const OUString* pDSNamesEnd = pDSNames + aDSNames.getLength();
197 :
198 0 : for ( ;pDSNames != pDSNamesEnd; ++pDSNames )
199 0 : m_pImpl->aDataSourceNames.insert( *pDSNames );
200 : }
201 : }
202 0 : catch( const Exception& )
203 : {
204 : OSL_FAIL( "ODataSourceContext::ODataSourceContext: caught an exception!" );
205 : }
206 0 : }
207 0 : ODataSourceContext::~ODataSourceContext()
208 : {
209 0 : delete(m_pImpl);
210 0 : }
211 :
212 :
213 0 : OUString& ODataSourceContext::disambiguate(OUString& _rDataSourceName)
214 : {
215 0 : OUString sCheck( _rDataSourceName );
216 0 : StringBag::const_iterator aPos = m_pImpl->aDataSourceNames.find( sCheck );
217 :
218 0 : sal_Int32 nPostfix = 1;
219 0 : while ( ( m_pImpl->aDataSourceNames.end() != aPos ) && ( nPostfix < 65535 ) )
220 : { // there already is a data source with this name
221 0 : sCheck = _rDataSourceName;
222 0 : sCheck += OUString::number( nPostfix++ );
223 :
224 0 : aPos = m_pImpl->aDataSourceNames.find( sCheck );
225 : }
226 :
227 0 : _rDataSourceName = sCheck;
228 0 : return _rDataSourceName;
229 : }
230 :
231 :
232 0 : void ODataSourceContext::getDataSourceNames( StringBag& _rNames ) const SAL_THROW (( ))
233 : {
234 0 : _rNames = m_pImpl->aDataSourceNames;
235 0 : }
236 :
237 :
238 0 : ODataSource ODataSourceContext::createNewLDAP( const OUString& _rName) SAL_THROW (( ))
239 : {
240 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:ldap:" );
241 : }
242 :
243 :
244 0 : ODataSource ODataSourceContext::createNewMORK( const OUString& _rName) SAL_THROW (( ))
245 : {
246 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:mozilla" );
247 : }
248 :
249 :
250 0 : ODataSource ODataSourceContext::createNewThunderbird( const OUString& _rName ) SAL_THROW (( ))
251 : {
252 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:thunderbird" );
253 : }
254 :
255 :
256 0 : ODataSource ODataSourceContext::createNewEvolutionLdap( const OUString& _rName) SAL_THROW (( ))
257 : {
258 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:ldap" );
259 : }
260 :
261 0 : ODataSource ODataSourceContext::createNewEvolutionGroupwise( const OUString& _rName) SAL_THROW (( ))
262 : {
263 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:groupwise" );
264 : }
265 :
266 0 : ODataSource ODataSourceContext::createNewEvolution( const OUString& _rName) SAL_THROW (( ))
267 : {
268 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:local" );
269 : }
270 :
271 :
272 0 : ODataSource ODataSourceContext::createNewKab( const OUString& _rName) SAL_THROW (( ))
273 : {
274 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:kab" );
275 : }
276 :
277 :
278 0 : ODataSource ODataSourceContext::createNewMacab( const OUString& _rName) SAL_THROW (( ))
279 : {
280 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:macab" );
281 : }
282 :
283 :
284 0 : ODataSource ODataSourceContext::createNewOutlook( const OUString& _rName) SAL_THROW (( ))
285 : {
286 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:outlook" );
287 : }
288 :
289 :
290 0 : ODataSource ODataSourceContext::createNewOE( const OUString& _rName) SAL_THROW (( ))
291 : {
292 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:outlookexp" );
293 : }
294 :
295 :
296 0 : ODataSource ODataSourceContext::createNewDBase( const OUString& _rName) SAL_THROW (( ))
297 : {
298 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:dbase:" );
299 : }
300 :
301 :
302 : //= ODataSourceImpl
303 :
304 0 : struct ODataSourceImpl
305 : {
306 : public:
307 : Reference< XComponentContext > xORB; /// the service factory
308 : Reference< XPropertySet > xDataSource; /// the UNO data source
309 : ::utl::SharedUNOComponent< XConnection >
310 : xConnection;
311 : StringBag aTables; // the cached table names
312 : OUString sName;
313 : sal_Bool bTablesUpToDate; // table name cache up-to-date?
314 :
315 0 : ODataSourceImpl( const Reference< XComponentContext >& _rxORB )
316 : :xORB( _rxORB )
317 0 : ,bTablesUpToDate( sal_False )
318 : {
319 0 : }
320 :
321 : ODataSourceImpl( const ODataSourceImpl& _rSource );
322 : };
323 :
324 :
325 0 : ODataSourceImpl::ODataSourceImpl( const ODataSourceImpl& _rSource )
326 : :xORB( _rSource.xORB )
327 : ,xDataSource( _rSource.xDataSource )
328 : ,xConnection( _rSource.xConnection )
329 : ,aTables( _rSource.aTables )
330 : ,sName( _rSource.sName )
331 0 : ,bTablesUpToDate( _rSource.bTablesUpToDate )
332 : {
333 0 : }
334 :
335 :
336 : //= ODataSource
337 :
338 :
339 0 : ODataSource::ODataSource( const ODataSource& _rSource )
340 0 : :m_pImpl( NULL )
341 : {
342 0 : *this = _rSource;
343 0 : }
344 :
345 :
346 0 : ODataSource& ODataSource::operator=( const ODataSource& _rSource )
347 : {
348 0 : if( this != &_rSource )
349 : {
350 0 : delete m_pImpl;
351 0 : m_pImpl = new ODataSourceImpl( *_rSource.m_pImpl );
352 : }
353 0 : return *this;
354 : }
355 :
356 :
357 0 : ODataSource::ODataSource( const Reference< XComponentContext >& _rxORB )
358 0 : :m_pImpl(new ODataSourceImpl(_rxORB))
359 : {
360 0 : }
361 :
362 :
363 0 : ODataSource::~ODataSource( )
364 : {
365 0 : delete m_pImpl;
366 0 : }
367 :
368 :
369 0 : void ODataSource::store() SAL_THROW (( ))
370 : {
371 0 : if (!isValid())
372 : // nothing to do
373 0 : return;
374 : try
375 : {
376 0 : Reference< XDocumentDataSource > xDocAccess( m_pImpl->xDataSource, UNO_QUERY );
377 0 : Reference< XStorable > xStorable;
378 0 : if ( xDocAccess.is() )
379 0 : xStorable = xStorable.query( xDocAccess->getDatabaseDocument() );
380 : OSL_ENSURE( xStorable.is(),"DataSource is no XStorable!" );
381 0 : if ( xStorable.is() )
382 0 : xStorable->storeAsURL(m_pImpl->sName,Sequence<PropertyValue>());
383 : }
384 0 : catch(const Exception&)
385 : {
386 : OSL_FAIL( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
387 : }
388 : }
389 :
390 0 : void ODataSource::registerDataSource( const OUString& _sRegisteredDataSourceName) SAL_THROW (( ))
391 : {
392 0 : if (!isValid())
393 : // nothing to do
394 0 : return;
395 :
396 : try
397 : {
398 : // invalidate ourself
399 0 : lcl_registerDataSource(m_pImpl->xORB,_sRegisteredDataSourceName,m_pImpl->sName);
400 : }
401 0 : catch(const Exception&)
402 : {
403 : OSL_FAIL( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
404 : }
405 : }
406 :
407 :
408 0 : void ODataSource::setDataSource( const Reference< XPropertySet >& _rxDS,const OUString& _sName, PackageAccessControl )
409 : {
410 0 : if (m_pImpl->xDataSource.get() == _rxDS.get())
411 : // nothing to do
412 0 : return;
413 :
414 0 : if ( isConnected() )
415 0 : disconnect();
416 :
417 0 : m_pImpl->sName = _sName;
418 0 : m_pImpl->xDataSource = _rxDS;
419 : }
420 :
421 :
422 0 : void ODataSource::remove() SAL_THROW (( ))
423 : {
424 0 : if (!isValid())
425 : // nothing to do
426 0 : return;
427 :
428 : try
429 : {
430 : // invalidate ourself
431 0 : m_pImpl->xDataSource.clear();
432 : }
433 0 : catch(const Exception&)
434 : {
435 : OSL_FAIL( "ODataSource::remove: caught an exception while creating the data source!" );
436 : }
437 : }
438 :
439 :
440 0 : sal_Bool ODataSource::rename( const OUString& _rName ) SAL_THROW (( ))
441 : {
442 0 : if (!isValid())
443 : // nothing to do
444 0 : return sal_False;
445 :
446 0 : m_pImpl->sName = _rName;
447 0 : return sal_True;
448 : }
449 :
450 :
451 0 : OUString ODataSource::getName() const SAL_THROW (( ))
452 : {
453 0 : if ( !isValid() )
454 0 : return OUString();
455 0 : return m_pImpl->sName;
456 : }
457 :
458 :
459 0 : bool ODataSource::hasTable( const OUString& _rTableName ) const
460 : {
461 0 : if ( !isConnected() )
462 0 : return false;
463 :
464 0 : const StringBag& aTables( getTableNames() );
465 0 : return aTables.find( _rTableName ) != aTables.end();
466 : }
467 :
468 :
469 0 : const StringBag& ODataSource::getTableNames() const SAL_THROW (( ))
470 : {
471 0 : m_pImpl->aTables.clear();
472 0 : if ( !isConnected() )
473 : {
474 : OSL_FAIL( "ODataSource::getTableNames: not connected!" );
475 : }
476 : else
477 : {
478 : try
479 : {
480 : // get the tables container from the connection
481 0 : Reference< XTablesSupplier > xSuppTables( m_pImpl->xConnection.getTyped(), UNO_QUERY );
482 0 : Reference< XNameAccess > xTables;
483 0 : if ( xSuppTables.is( ) )
484 0 : xTables = xSuppTables->getTables();
485 : DBG_ASSERT( xTables.is(), "ODataSource::getTableNames: could not retrieve the tables container!" );
486 :
487 : // get the names
488 0 : Sequence< OUString > aTableNames;
489 0 : if ( xTables.is( ) )
490 0 : aTableNames = xTables->getElementNames( );
491 :
492 : // copy the names
493 0 : const OUString* pTableNames = aTableNames.getConstArray();
494 0 : const OUString* pTableNamesEnd = pTableNames + aTableNames.getLength();
495 0 : for (;pTableNames < pTableNamesEnd; ++pTableNames)
496 0 : m_pImpl->aTables.insert( *pTableNames );
497 : }
498 0 : catch(const Exception&)
499 : {
500 : }
501 : }
502 :
503 : // now the table cache is up-to-date
504 0 : m_pImpl->bTablesUpToDate = sal_True;
505 0 : return m_pImpl->aTables;
506 : }
507 :
508 :
509 0 : sal_Bool ODataSource::connect( Window* _pMessageParent ) SAL_THROW (( ))
510 : {
511 0 : if ( isConnected( ) )
512 : // nothing to do
513 0 : return sal_True;
514 :
515 :
516 : // create the interaction handler (needed for authentication and error handling)
517 0 : Reference< XInteractionHandler > xInteractions;
518 : try
519 : {
520 : xInteractions.set(
521 : InteractionHandler::createWithParent(m_pImpl->xORB, 0),
522 0 : UNO_QUERY);
523 : }
524 0 : catch(const Exception&)
525 : {
526 : }
527 :
528 :
529 : // failure to create the interaction handler is a serious issue ...
530 0 : if (!xInteractions.is())
531 : {
532 0 : OUString s_sInteractionHandlerServiceName("com.sun.star.task.InteractionHandler");
533 0 : if ( _pMessageParent )
534 0 : ShowServiceNotAvailableError( _pMessageParent, s_sInteractionHandlerServiceName, true );
535 0 : return sal_False;
536 : }
537 :
538 :
539 : // open the connection
540 0 : Any aError;
541 0 : Reference< XConnection > xConnection;
542 : try
543 : {
544 0 : Reference< XCompletedConnection > xComplConn( m_pImpl->xDataSource, UNO_QUERY );
545 : DBG_ASSERT( xComplConn.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" );
546 0 : if ( xComplConn.is() )
547 0 : xConnection = xComplConn->connectWithCompletion( xInteractions );
548 : }
549 0 : catch( const SQLContext& e ) { aError <<= e; }
550 0 : catch( const SQLWarning& e ) { aError <<= e; }
551 0 : catch( const SQLException& e ) { aError <<= e; }
552 0 : catch( const Exception& )
553 : {
554 : OSL_FAIL( "ODataSource::connect: caught a generic exception!" );
555 : }
556 :
557 :
558 : // handle errors
559 0 : if ( aError.hasValue() && _pMessageParent )
560 : {
561 : try
562 : {
563 0 : SQLException aException;
564 0 : aError >>= aException;
565 0 : if ( aException.Message.isEmpty() )
566 : {
567 : // prepend some context info
568 0 : SQLContext aDetailedError;
569 0 : aDetailedError.Message = ModuleRes(RID_STR_NOCONNECTION).toString();
570 0 : aDetailedError.Details = ModuleRes(RID_STR_PLEASECHECKSETTINGS).toString();
571 0 : aDetailedError.NextException = aError;
572 : // handle (aka display) the new context info
573 0 : xInteractions->handle( new OInteractionRequest( makeAny( aDetailedError ) ) );
574 : }
575 : else
576 : {
577 : // handle (aka display) the original error
578 0 : xInteractions->handle( new OInteractionRequest( makeAny( aException ) ) );
579 0 : }
580 : }
581 0 : catch( const Exception& )
582 : {
583 : OSL_FAIL( "ODataSource::connect: caught an exception while trying to display the error!" );
584 : }
585 : }
586 :
587 0 : if ( !xConnection.is() )
588 0 : return sal_False;
589 :
590 :
591 : // success
592 0 : m_pImpl->xConnection.reset( xConnection );
593 0 : m_pImpl->aTables.clear();
594 0 : m_pImpl->bTablesUpToDate = sal_False;
595 :
596 0 : return sal_True;
597 : }
598 :
599 :
600 0 : void ODataSource::disconnect( ) SAL_THROW (( ))
601 : {
602 0 : m_pImpl->xConnection.clear();
603 0 : m_pImpl->aTables.clear();
604 0 : m_pImpl->bTablesUpToDate = sal_False;
605 0 : }
606 :
607 :
608 0 : sal_Bool ODataSource::isConnected( ) const SAL_THROW (( ))
609 : {
610 0 : return m_pImpl->xConnection.is();
611 : }
612 :
613 :
614 0 : sal_Bool ODataSource::isValid() const SAL_THROW (( ))
615 : {
616 0 : return m_pImpl && m_pImpl->xDataSource.is();
617 : }
618 :
619 0 : Reference< XPropertySet > ODataSource::getDataSource() const SAL_THROW (( ))
620 : {
621 0 : return m_pImpl ? m_pImpl->xDataSource : Reference< XPropertySet >();
622 : }
623 :
624 :
625 : } // namespace abp
626 :
627 :
628 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|