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 : #include <config_folders.h>
21 :
22 : #include "hsqldb/HDriver.hxx"
23 : #include "hsqldb/HConnection.hxx"
24 : #include <osl/diagnose.h>
25 : #include <connectivity/dbexception.hxx>
26 : #include <com/sun/star/configuration/theDefaultProvider.hpp>
27 : #include <com/sun/star/sdbc/DriverManager.hpp>
28 : #include <com/sun/star/sdbc/XDriverAccess.hpp>
29 : #include <com/sun/star/sdbc/XResultSet.hpp>
30 : #include <com/sun/star/sdbc/XRow.hpp>
31 : #include <com/sun/star/embed/XTransactionBroadcaster.hpp>
32 : #include <com/sun/star/embed/ElementModes.hpp>
33 : #include "TConnection.hxx"
34 : #include "hsqldb/HStorageMap.hxx"
35 : #include <jvmfwk/framework.h>
36 : #include <com/sun/star/reflection/XProxyFactory.hpp>
37 : #include <com/sun/star/embed/XStorage.hpp>
38 : #include <com/sun/star/frame/Desktop.hpp>
39 : #include <com/sun/star/lang/Locale.hpp>
40 : #include <com/sun/star/util/XFlushable.hpp>
41 : #include "HTerminateListener.hxx"
42 : #include "hsqldb/HCatalog.hxx"
43 : #include "diagnose_ex.h"
44 : #include <rtl/ustrbuf.hxx>
45 : #include <osl/file.h>
46 : #include <osl/process.h>
47 : #include <comphelper/namedvaluecollection.hxx>
48 : #include <comphelper/processfactory.hxx>
49 : #include <comphelper/string.hxx>
50 : #include <cppuhelper/supportsservice.hxx>
51 : #include <unotools/confignode.hxx>
52 : #include <unotools/ucbstreamhelper.hxx>
53 : #include "resource/hsqldb_res.hrc"
54 : #include "resource/sharedresources.hxx"
55 : #include <i18nlangtag/languagetag.hxx>
56 :
57 : #include <o3tl/compat_functional.hxx>
58 :
59 : #include <boost/scoped_ptr.hpp>
60 :
61 :
62 : namespace connectivity
63 : {
64 :
65 : using namespace hsqldb;
66 : using namespace ::com::sun::star::uno;
67 : using namespace ::com::sun::star::sdbc;
68 : using namespace ::com::sun::star::sdbcx;
69 : using namespace ::com::sun::star::beans;
70 : using namespace ::com::sun::star::frame;
71 : using namespace ::com::sun::star::lang;
72 : using namespace ::com::sun::star::embed;
73 : using namespace ::com::sun::star::io;
74 : using namespace ::com::sun::star::task;
75 : using namespace ::com::sun::star::util;
76 : using namespace ::com::sun::star::reflection;
77 :
78 : namespace hsqldb
79 : {
80 4 : Reference< XInterface > SAL_CALL ODriverDelegator_CreateInstance(const Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFac) throw( Exception )
81 : {
82 4 : return *(new ODriverDelegator(comphelper::getComponentContext(_rxFac)));
83 : }
84 : }
85 :
86 :
87 :
88 :
89 : //= ODriverDelegator
90 :
91 :
92 4 : ODriverDelegator::ODriverDelegator(const Reference< XComponentContext >& _rxContext)
93 : : ODriverDelegator_BASE(m_aMutex)
94 : ,m_xContext(_rxContext)
95 4 : ,m_bInShutDownConnections(false)
96 : {
97 4 : }
98 :
99 :
100 0 : ODriverDelegator::~ODriverDelegator()
101 : {
102 : try
103 : {
104 0 : ::comphelper::disposeComponent(m_xDriver);
105 : }
106 0 : catch(const Exception&)
107 : {
108 : }
109 0 : }
110 :
111 :
112 0 : void SAL_CALL ODriverDelegator::disposing()
113 : {
114 0 : ::osl::MutexGuard aGuard(m_aMutex);
115 :
116 : try
117 : {
118 0 : for (TWeakPairVector::iterator i = m_aConnections.begin(); m_aConnections.end() != i; ++i)
119 : {
120 0 : Reference<XInterface > xTemp = i->first.get();
121 0 : ::comphelper::disposeComponent(xTemp);
122 0 : }
123 : }
124 0 : catch(Exception&)
125 : {
126 : // not interested in
127 : }
128 0 : m_aConnections.clear();
129 0 : TWeakPairVector().swap(m_aConnections);
130 :
131 0 : cppu::WeakComponentImplHelperBase::disposing();
132 0 : }
133 :
134 4 : Reference< XDriver > ODriverDelegator::loadDriver( )
135 : {
136 4 : if ( !m_xDriver.is() )
137 : {
138 4 : OUString sURL("jdbc:hsqldb:db");
139 8 : Reference<XDriverManager2> xDriverAccess = DriverManager::create( m_xContext );
140 8 : m_xDriver = xDriverAccess->getDriverByURL(sURL);
141 : }
142 :
143 4 : return m_xDriver;
144 : }
145 :
146 :
147 : namespace
148 : {
149 4 : OUString lcl_getPermittedJavaMethods_nothrow( const Reference< XComponentContext >& _rxContext )
150 : {
151 4 : OUStringBuffer aConfigPath;
152 4 : aConfigPath.appendAscii( "/org.openoffice.Office.DataAccess/DriverSettings/" );
153 4 : aConfigPath.append ( ODriverDelegator::getImplementationName_Static() );
154 4 : aConfigPath.appendAscii( "/PermittedJavaMethods" );
155 : ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext(
156 8 : _rxContext, aConfigPath.makeStringAndClear() ) );
157 :
158 8 : OUStringBuffer aPermittedMethods;
159 8 : Sequence< OUString > aNodeNames( aConfig.getNodeNames() );
160 8 : for ( const OUString* pNodeNames = aNodeNames.getConstArray();
161 4 : pNodeNames != aNodeNames.getConstArray() + aNodeNames.getLength();
162 : ++pNodeNames
163 : )
164 : {
165 0 : OUString sPermittedMethod;
166 0 : OSL_VERIFY( aConfig.getNodeValue( *pNodeNames ) >>= sPermittedMethod );
167 :
168 0 : if ( !aPermittedMethods.isEmpty() )
169 0 : aPermittedMethods.append( ';' );
170 0 : aPermittedMethods.append( sPermittedMethod );
171 0 : }
172 :
173 8 : return aPermittedMethods.makeStringAndClear();
174 : }
175 : }
176 :
177 :
178 4 : Reference< XConnection > SAL_CALL ODriverDelegator::connect( const OUString& url, const Sequence< PropertyValue >& info ) throw (SQLException, RuntimeException, std::exception)
179 : {
180 4 : Reference< XConnection > xConnection;
181 4 : if ( acceptsURL(url) )
182 : {
183 4 : Reference< XDriver > xDriver = loadDriver();
184 4 : if ( xDriver.is() )
185 : {
186 4 : OUString sURL;
187 8 : Reference<XStorage> xStorage;
188 4 : const PropertyValue* pIter = info.getConstArray();
189 4 : const PropertyValue* pEnd = pIter + info.getLength();
190 :
191 20 : for (;pIter != pEnd; ++pIter)
192 : {
193 16 : if ( pIter->Name == "Storage" )
194 : {
195 4 : xStorage.set(pIter->Value,UNO_QUERY);
196 : }
197 12 : else if ( pIter->Name == "URL" )
198 : {
199 4 : pIter->Value >>= sURL;
200 : }
201 : }
202 :
203 4 : if ( !xStorage.is() || sURL.isEmpty() )
204 : {
205 0 : ::connectivity::SharedResources aResources;
206 0 : const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
207 0 : ::dbtools::throwGenericSQLException(sMessage ,*this);
208 : }
209 :
210 8 : OUString sSystemPath;
211 4 : osl_getSystemPathFromFileURL( sURL.pData, &sSystemPath.pData );
212 4 : if ( sURL.isEmpty() || sSystemPath.isEmpty() )
213 : {
214 0 : ::connectivity::SharedResources aResources;
215 0 : const OUString sMessage = aResources.getResourceString(STR_INVALID_FILE_URL);
216 0 : ::dbtools::throwGenericSQLException(sMessage ,*this);
217 : }
218 :
219 4 : bool bIsNewDatabase = !xStorage->hasElements();
220 :
221 8 : ::comphelper::NamedValueCollection aProperties;
222 :
223 : // properties for accessing the embedded storage
224 8 : OUString sKey = StorageContainer::registerStorage( xStorage, sSystemPath );
225 4 : aProperties.put( "storage_key", sKey );
226 : aProperties.put( "storage_class_name",
227 4 : OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageAccess" ) );
228 : aProperties.put( "fileaccess_class_name",
229 4 : OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageFileAccess" ) );
230 :
231 : // JDBC driver and driver's classpath
232 : aProperties.put( "JavaDriverClass",
233 4 : OUString( "org.hsqldb.jdbcDriver" ) );
234 : aProperties.put( "JavaDriverClassPath",
235 : OUString(
236 : #ifdef SYSTEM_HSQLDB
237 : HSQLDB_JAR
238 : #else
239 : "vnd.sun.star.expand:$LO_JAVA_DIR/hsqldb.jar"
240 : #endif
241 : " vnd.sun.star.expand:$LO_JAVA_DIR/sdbc_hsqldb.jar"
242 4 : ) );
243 :
244 : // auto increment handling
245 4 : aProperties.put( "IsAutoRetrievingEnabled", true );
246 : aProperties.put( "AutoRetrievingStatement",
247 4 : OUString( "CALL IDENTITY()" ) );
248 4 : aProperties.put( "IgnoreDriverPrivileges", true );
249 :
250 : // don't want to expose HSQLDB's schema capabilities which exist since 1.8.0RC10
251 : aProperties.put( "default_schema",
252 4 : OUString( "true" ) );
253 :
254 : // security: permitted Java classes
255 : NamedValue aPermittedClasses(
256 : OUString( "hsqldb.method_class_names" ),
257 : makeAny( lcl_getPermittedJavaMethods_nothrow( m_xContext ) )
258 8 : );
259 4 : aProperties.put( "SystemProperties", Sequence< NamedValue >( &aPermittedClasses, 1 ) );
260 :
261 8 : const OUString sProperties( "properties" );
262 8 : OUString sMessage;
263 : try
264 : {
265 4 : if ( !bIsNewDatabase && xStorage->isStreamElement(sProperties) )
266 : {
267 4 : Reference<XStream > xStream = xStorage->openStreamElement(sProperties,ElementModes::READ);
268 4 : if ( xStream.is() )
269 : {
270 4 : boost::scoped_ptr<SvStream> pStream( ::utl::UcbStreamHelper::CreateStream(xStream) );
271 4 : if ( pStream.get() )
272 : {
273 4 : OString sLine;
274 8 : OString sVersionString;
275 80 : while ( pStream->ReadLine(sLine) )
276 : {
277 72 : if ( sLine.isEmpty() )
278 0 : continue;
279 72 : const OString sIniKey = comphelper::string::getToken(sLine, 0, '=');
280 144 : const OString sValue = comphelper::string::getToken(sLine, 1, '=');
281 72 : if( sIniKey == "hsqldb.compatible_version" )
282 : {
283 4 : sVersionString = sValue;
284 : }
285 : else
286 : {
287 68 : if (sIniKey == "version" && sVersionString.isEmpty())
288 : {
289 4 : sVersionString = sValue;
290 : }
291 : }
292 72 : }
293 4 : if (!sVersionString.isEmpty())
294 : {
295 : using comphelper::string::getToken;
296 4 : const sal_Int32 nMajor = getToken(sVersionString, 0, '.').toInt32();
297 4 : const sal_Int32 nMinor = getToken(sVersionString, 1, '.').toInt32();
298 4 : const sal_Int32 nMicro = getToken(sVersionString, 2, '.').toInt32();
299 4 : if ( nMajor > 1
300 4 : || ( nMajor == 1 && nMinor > 8 )
301 4 : || ( nMajor == 1 && nMinor == 8 && nMicro > 0 ) )
302 : {
303 0 : ::connectivity::SharedResources aResources;
304 0 : sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
305 : }
306 4 : }
307 4 : }
308 : } // if ( xStream.is() )
309 4 : ::comphelper::disposeComponent(xStream);
310 : }
311 : }
312 0 : catch(Exception&)
313 : {
314 : }
315 4 : if ( !sMessage.isEmpty() )
316 : {
317 0 : ::dbtools::throwGenericSQLException(sMessage ,*this);
318 : }
319 :
320 : // readonly?
321 8 : Reference<XPropertySet> xProp(xStorage,UNO_QUERY);
322 4 : if ( xProp.is() )
323 : {
324 4 : sal_Int32 nMode = 0;
325 4 : xProp->getPropertyValue("OpenMode") >>= nMode;
326 4 : if ( (nMode & ElementModes::WRITE) != ElementModes::WRITE )
327 : {
328 0 : aProperties.put( "readonly", OUString( "true" ) );
329 : }
330 : }
331 :
332 8 : Sequence< PropertyValue > aConnectionArgs;
333 4 : aProperties >>= aConnectionArgs;
334 :
335 8 : OUString sConnectURL("jdbc:hsqldb:");
336 :
337 4 : sConnectURL += sSystemPath;
338 8 : Reference<XConnection> xOrig;
339 : try
340 : {
341 4 : xOrig = xDriver->connect( sConnectURL, aConnectionArgs );
342 : }
343 0 : catch(const Exception& e)
344 : {
345 0 : StorageContainer::revokeStorage(sKey,NULL);
346 : (void)e;
347 0 : throw;
348 : }
349 :
350 : // if the storage is completely empty, then we just created a new HSQLDB
351 : // In this case, do some initializations.
352 4 : if ( bIsNewDatabase && xOrig.is() )
353 0 : onConnectedNewDatabase( xOrig );
354 :
355 4 : if ( xOrig.is() )
356 : {
357 4 : OMetaConnection* pMetaConnection = NULL;
358 : // now we have to set the URL to get the correct answer for metadata()->getURL()
359 4 : Reference< XUnoTunnel> xTunnel(xOrig,UNO_QUERY);
360 4 : if ( xTunnel.is() )
361 : {
362 4 : pMetaConnection = reinterpret_cast<OMetaConnection*>(xTunnel->getSomething( OMetaConnection::getUnoTunnelImplementationId() ));
363 4 : if ( pMetaConnection )
364 4 : pMetaConnection->setURL(url);
365 : }
366 :
367 8 : Reference<XComponent> xComp(xOrig,UNO_QUERY);
368 4 : if ( xComp.is() )
369 4 : xComp->addEventListener(this);
370 :
371 : // we want to close all connections when the office shuts down
372 4 : static Reference< XTerminateListener> s_xTerminateListener;
373 4 : if( !s_xTerminateListener.is() )
374 : {
375 4 : Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext );
376 :
377 4 : s_xTerminateListener = new OConnectionController(this);
378 4 : xDesktop->addTerminateListener(s_xTerminateListener);
379 : }
380 8 : Reference< XComponent> xIfc = new OHsqlConnection( this, xOrig, m_xContext );
381 4 : xConnection.set(xIfc,UNO_QUERY);
382 4 : m_aConnections.push_back(TWeakPair(WeakReferenceHelper(xOrig),TWeakConnectionPair(sKey,TWeakRefPair(WeakReferenceHelper(xConnection),WeakReferenceHelper()))));
383 :
384 8 : Reference<XTransactionBroadcaster> xBroad(xStorage,UNO_QUERY);
385 4 : if ( xBroad.is() )
386 : {
387 4 : Reference<XTransactionListener> xListener(*this,UNO_QUERY);
388 4 : xBroad->addTransactionListener(xListener);
389 4 : }
390 4 : }
391 4 : }
392 : }
393 4 : return xConnection;
394 : }
395 :
396 :
397 24 : sal_Bool SAL_CALL ODriverDelegator::acceptsURL( const OUString& url ) throw (SQLException, RuntimeException, std::exception)
398 : {
399 24 : sal_Bool bEnabled = sal_False;
400 24 : javaFrameworkError e = jfw_getEnabled(&bEnabled);
401 24 : switch (e) {
402 : case JFW_E_NONE:
403 24 : break;
404 : case JFW_E_DIRECT_MODE:
405 : SAL_INFO(
406 : "connectivity.hsqldb",
407 : "jfw_getEnabled: JFW_E_DIRECT_MODE, assuming true");
408 0 : bEnabled = true;
409 0 : break;
410 : default:
411 : SAL_WARN(
412 : "connectivity.hsqldb", "jfw_getEnabled: error code " << +e);
413 0 : break;
414 : }
415 24 : return bEnabled && url.equals("sdbc:embedded:hsqldb");
416 : }
417 :
418 :
419 4 : Sequence< DriverPropertyInfo > SAL_CALL ODriverDelegator::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) throw (SQLException, RuntimeException, std::exception)
420 : {
421 4 : if ( !acceptsURL(url) )
422 0 : return Sequence< DriverPropertyInfo >();
423 4 : ::std::vector< DriverPropertyInfo > aDriverInfo;
424 : aDriverInfo.push_back(DriverPropertyInfo(
425 : OUString("Storage")
426 : ,OUString("Defines the storage where the database will be stored.")
427 : ,sal_True
428 : ,OUString()
429 : ,Sequence< OUString >())
430 4 : );
431 : aDriverInfo.push_back(DriverPropertyInfo(
432 : OUString("URL")
433 : ,OUString("Defines the url of the data source.")
434 : ,sal_True
435 : ,OUString()
436 : ,Sequence< OUString >())
437 4 : );
438 : aDriverInfo.push_back(DriverPropertyInfo(
439 : OUString("AutoRetrievingStatement")
440 : ,OUString("Defines the statement which will be executed to retrieve auto increment values.")
441 : ,sal_False
442 : ,OUString("CALL IDENTITY()")
443 : ,Sequence< OUString >())
444 4 : );
445 4 : return Sequence< DriverPropertyInfo >(&aDriverInfo[0],aDriverInfo.size());
446 : }
447 :
448 :
449 0 : sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion( ) throw (RuntimeException, std::exception)
450 : {
451 0 : return 1;
452 : }
453 :
454 :
455 0 : sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion( ) throw (RuntimeException, std::exception)
456 : {
457 0 : return 0;
458 : }
459 :
460 :
461 4 : Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByConnection( const Reference< XConnection >& connection ) throw (SQLException, RuntimeException, std::exception)
462 : {
463 4 : ::osl::MutexGuard aGuard( m_aMutex );
464 4 : checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed);
465 :
466 4 : Reference< XTablesSupplier > xTab;
467 :
468 4 : TWeakPairVector::iterator aEnd = m_aConnections.end();
469 4 : for (TWeakPairVector::iterator i = m_aConnections.begin(); aEnd != i; ++i)
470 : {
471 4 : if ( i->second.second.first.get() == connection.get() )
472 : {
473 4 : xTab = Reference< XTablesSupplier >(i->second.second.second.get().get(),UNO_QUERY);
474 4 : if ( !xTab.is() )
475 : {
476 4 : xTab = new OHCatalog(connection);
477 4 : i->second.second.second = WeakReferenceHelper(xTab);
478 : }
479 4 : break;
480 : }
481 : }
482 :
483 4 : return xTab;
484 : }
485 :
486 :
487 0 : Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info ) throw (SQLException, RuntimeException, std::exception)
488 : {
489 0 : if ( ! acceptsURL(url) )
490 : {
491 0 : ::connectivity::SharedResources aResources;
492 0 : const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
493 0 : ::dbtools::throwGenericSQLException(sMessage ,*this);
494 : }
495 :
496 0 : return getDataDefinitionByConnection(connect(url,info));
497 : }
498 :
499 : // XServiceInfo
500 :
501 :
502 8 : OUString ODriverDelegator::getImplementationName_Static( ) throw(RuntimeException)
503 : {
504 8 : return OUString("com.sun.star.sdbcx.comp.hsqldb.Driver");
505 : }
506 :
507 4 : Sequence< OUString > ODriverDelegator::getSupportedServiceNames_Static( ) throw (RuntimeException)
508 : {
509 4 : Sequence< OUString > aSNS( 2 );
510 4 : aSNS[0] = "com.sun.star.sdbc.Driver";
511 4 : aSNS[1] = "com.sun.star.sdbcx.Driver";
512 4 : return aSNS;
513 : }
514 :
515 0 : OUString SAL_CALL ODriverDelegator::getImplementationName( ) throw(RuntimeException, std::exception)
516 : {
517 0 : return getImplementationName_Static();
518 : }
519 :
520 0 : sal_Bool SAL_CALL ODriverDelegator::supportsService( const OUString& _rServiceName ) throw(RuntimeException, std::exception)
521 : {
522 0 : return cppu::supportsService(this, _rServiceName);
523 : }
524 :
525 0 : Sequence< OUString > SAL_CALL ODriverDelegator::getSupportedServiceNames( ) throw(RuntimeException, std::exception)
526 : {
527 0 : return getSupportedServiceNames_Static();
528 : }
529 :
530 0 : void SAL_CALL ODriverDelegator::createCatalog( const Sequence< PropertyValue >& /*info*/ ) throw (SQLException, ::com::sun::star::container::ElementExistException, RuntimeException, std::exception)
531 : {
532 0 : ::dbtools::throwFeatureNotImplementedSQLException( "XCreateCatalog::createCatalog", *this );
533 0 : }
534 :
535 2 : void ODriverDelegator::shutdownConnection(const TWeakPairVector::iterator& _aIter )
536 : {
537 : OSL_ENSURE(m_aConnections.end() != _aIter,"Iterator equals .end()");
538 2 : bool bLastOne = true;
539 : try
540 : {
541 2 : Reference<XConnection> _xConnection(_aIter->first.get(),UNO_QUERY);
542 :
543 2 : if ( _xConnection.is() )
544 : {
545 2 : Reference<XStatement> xStmt = _xConnection->createStatement();
546 2 : if ( xStmt.is() )
547 : {
548 2 : Reference<XResultSet> xRes(xStmt->executeQuery(OUString("SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS WHERE USER_NAME ='SA'")),UNO_QUERY);
549 4 : Reference<XRow> xRow(xRes,UNO_QUERY);
550 2 : if ( xRow.is() && xRes->next() )
551 2 : bLastOne = xRow->getInt(1) == 1;
552 2 : if ( bLastOne )
553 4 : xStmt->execute(OUString("SHUTDOWN"));
554 2 : }
555 2 : }
556 : }
557 0 : catch(Exception&)
558 : {
559 : }
560 2 : if ( bLastOne )
561 : {
562 : // Reference<XTransactionListener> xListener(*this,UNO_QUERY);
563 : // a shutdown should commit all changes to the db files
564 2 : StorageContainer::revokeStorage(_aIter->second.first,NULL);
565 : }
566 2 : if ( !m_bInShutDownConnections )
567 2 : m_aConnections.erase(_aIter);
568 2 : }
569 :
570 4 : void SAL_CALL ODriverDelegator::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(::com::sun::star::uno::RuntimeException, std::exception)
571 : {
572 4 : ::osl::MutexGuard aGuard(m_aMutex);
573 8 : Reference<XConnection> xCon(Source.Source,UNO_QUERY);
574 4 : if ( xCon.is() )
575 : {
576 2 : TWeakPairVector::iterator i = m_aConnections.begin();
577 2 : for (; m_aConnections.end() != i; ++i)
578 : {
579 2 : if ( i->first.get() == xCon.get() )
580 : {
581 2 : shutdownConnection(i);
582 2 : break;
583 : }
584 : }
585 : }
586 : else
587 : {
588 2 : Reference< XStorage> xStorage(Source.Source,UNO_QUERY);
589 2 : if ( xStorage.is() )
590 : {
591 2 : OUString sKey = StorageContainer::getRegisteredKey(xStorage);
592 : TWeakPairVector::iterator i = ::std::find_if(m_aConnections.begin(),m_aConnections.end(),::o3tl::compose1(
593 : ::std::bind2nd(::std::equal_to< OUString >(),sKey)
594 2 : ,::o3tl::compose1(::o3tl::select1st<TWeakConnectionPair>(),::o3tl::select2nd< TWeakPair >())));
595 2 : if ( i != m_aConnections.end() )
596 0 : shutdownConnection(i);
597 2 : }
598 4 : }
599 4 : }
600 :
601 0 : void ODriverDelegator::shutdownConnections()
602 : {
603 0 : m_bInShutDownConnections = true;
604 0 : TWeakPairVector::iterator aEnd = m_aConnections.end();
605 0 : for (TWeakPairVector::iterator i = m_aConnections.begin(); aEnd != i; ++i)
606 : {
607 : try
608 : {
609 0 : Reference<XConnection> xCon(i->first,UNO_QUERY);
610 0 : ::comphelper::disposeComponent(xCon);
611 : }
612 0 : catch(Exception&)
613 : {
614 : }
615 : }
616 0 : m_aConnections.clear();
617 0 : m_bInShutDownConnections = true;
618 0 : }
619 :
620 0 : void ODriverDelegator::flushConnections()
621 : {
622 0 : TWeakPairVector::iterator aEnd = m_aConnections.end();
623 0 : for (TWeakPairVector::iterator i = m_aConnections.begin(); aEnd != i; ++i)
624 : {
625 : try
626 : {
627 0 : Reference<XFlushable> xCon(i->second.second.first.get(),UNO_QUERY);
628 0 : xCon->flush();
629 : }
630 0 : catch(Exception&)
631 : {
632 : }
633 : }
634 0 : }
635 :
636 2 : void SAL_CALL ODriverDelegator::preCommit( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException, std::exception)
637 : {
638 2 : ::osl::MutexGuard aGuard(m_aMutex);
639 :
640 4 : Reference< XStorage> xStorage(aEvent.Source,UNO_QUERY);
641 4 : OUString sKey = StorageContainer::getRegisteredKey(xStorage);
642 2 : if ( !sKey.isEmpty() )
643 : {
644 : TWeakPairVector::iterator i = ::std::find_if(m_aConnections.begin(),m_aConnections.end(),::o3tl::compose1(
645 : ::std::bind2nd(::std::equal_to< OUString >(),sKey)
646 0 : ,::o3tl::compose1(::o3tl::select1st<TWeakConnectionPair>(),::o3tl::select2nd< TWeakPair >())));
647 : OSL_ENSURE( i != m_aConnections.end(), "ODriverDelegator::preCommit: they're committing a storage which I do not know!" );
648 0 : if ( i != m_aConnections.end() )
649 : {
650 : try
651 : {
652 0 : Reference<XConnection> xConnection(i->first,UNO_QUERY);
653 0 : if ( xConnection.is() )
654 : {
655 0 : Reference< XStatement> xStmt = xConnection->createStatement();
656 : OSL_ENSURE( xStmt.is(), "ODriverDelegator::preCommit: no statement!" );
657 0 : if ( xStmt.is() )
658 0 : xStmt->execute( OUString( "SET WRITE_DELAY 0" ) );
659 :
660 0 : bool bPreviousAutoCommit = xConnection->getAutoCommit();
661 0 : xConnection->setAutoCommit( sal_False );
662 0 : xConnection->commit();
663 0 : xConnection->setAutoCommit( bPreviousAutoCommit );
664 :
665 0 : if ( xStmt.is() )
666 0 : xStmt->execute( OUString( "SET WRITE_DELAY 60" ) );
667 0 : }
668 : }
669 0 : catch(Exception&)
670 : {
671 : OSL_FAIL( "ODriverDelegator::preCommit: caught an exception!" );
672 : }
673 : }
674 2 : }
675 2 : }
676 :
677 2 : void SAL_CALL ODriverDelegator::commited( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) throw (::com::sun::star::uno::RuntimeException, std::exception)
678 : {
679 2 : }
680 :
681 0 : void SAL_CALL ODriverDelegator::preRevert( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException, std::exception)
682 : {
683 0 : }
684 :
685 0 : void SAL_CALL ODriverDelegator::reverted( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) throw (::com::sun::star::uno::RuntimeException, std::exception)
686 : {
687 0 : }
688 :
689 : namespace
690 : {
691 :
692 0 : const sal_Char* lcl_getCollationForLocale( const OUString& _rLocaleString, bool _bAcceptCountryMismatch = false )
693 : {
694 : static const sal_Char* pTranslations[] =
695 : {
696 : "af-ZA", "Afrikaans",
697 : "am-ET", "Amharic",
698 : "ar", "Arabic",
699 : "as-IN", "Assamese",
700 : "az-AZ", "Azerbaijani_Latin",
701 : "az-cyrillic", "Azerbaijani_Cyrillic",
702 : "be-BY", "Belarusian",
703 : "bg-BG", "Bulgarian",
704 : "bn-IN", "Bengali",
705 : "bo-CN", "Tibetan",
706 : "bs-BA", "Bosnian",
707 : "ca-ES", "Catalan",
708 : "cs-CZ", "Czech",
709 : "cy-GB", "Welsh",
710 : "da-DK", "Danish",
711 : "de-DE", "German",
712 : "el-GR", "Greek",
713 : "en-US", "Latin1_General",
714 : "es-ES", "Spanish",
715 : "et-EE", "Estonian",
716 : "eu", "Basque",
717 : "fi-FI", "Finnish",
718 : "fr-FR", "French",
719 : "gn-PY", "Guarani",
720 : "gu-IN", "Gujarati",
721 : "ha-NG", "Hausa",
722 : "he-IL", "Hebrew",
723 : "hi-IN", "Hindi",
724 : "hr-HR", "Croatian",
725 : "hu-HU", "Hungarian",
726 : "hy-AM", "Armenian",
727 : "id-ID", "Indonesian",
728 : "ig-NG", "Igbo",
729 : "is-IS", "Icelandic",
730 : "it-IT", "Italian",
731 : "iu-CA", "Inuktitut",
732 : "ja-JP", "Japanese",
733 : "ka-GE", "Georgian",
734 : "kk-KZ", "Kazakh",
735 : "km-KH", "Khmer",
736 : "kn-IN", "Kannada",
737 : "ko-KR", "Korean",
738 : "kok-IN", "Konkani",
739 : "ks", "Kashmiri",
740 : "ky-KG", "Kirghiz",
741 : "lo-LA", "Lao",
742 : "lt-LT", "Lithuanian",
743 : "lv-LV", "Latvian",
744 : "mi-NZ", "Maori",
745 : "mk-MK", "Macedonian",
746 : "ml-IN", "Malayalam",
747 : "mn-MN", "Mongolian",
748 : "mni-IN", "Manipuri",
749 : "mr-IN", "Marathi",
750 : "ms-MY", "Malay",
751 : "mt-MT", "Maltese",
752 : "my-MM", "Burmese",
753 : "nb-NO", "Danish_Norwegian",
754 : "ne-NP", "Nepali",
755 : "nl-NL", "Dutch",
756 : "nn-NO", "Norwegian",
757 : "or-IN", "Odia",
758 : "pa-IN", "Punjabi",
759 : "pl-PL", "Polish",
760 : "ps-AF", "Pashto",
761 : "pt-PT", "Portuguese",
762 : "ro-RO", "Romanian",
763 : "ru-RU", "Russian",
764 : "sa-IN", "Sanskrit",
765 : "sd-IN", "Sindhi",
766 : "sk-SK", "Slovak",
767 : "sl-SI", "Slovenian",
768 : "so-SO", "Somali",
769 : "sq-AL", "Albanian",
770 : "sr-YU", "Serbian_Cyrillic",
771 : "sv-SE", "Swedish",
772 : "sw-KE", "Swahili",
773 : "ta-IN", "Tamil",
774 : "te-IN", "Telugu",
775 : "tg-TJ", "Tajik",
776 : "th-TH", "Thai",
777 : "tk-TM", "Turkmen",
778 : "tn-BW", "Tswana",
779 : "tr-TR", "Turkish",
780 : "tt-RU", "Tatar",
781 : "uk-UA", "Ukrainian",
782 : "ur-PK", "Urdu",
783 : "uz-UZ", "Uzbek_Latin",
784 : "ven-ZA", "Venda",
785 : "vi-VN", "Vietnamese",
786 : "yo-NG", "Yoruba",
787 : "zh-CN", "Chinese",
788 : "zu-ZA", "Zulu",
789 : NULL, NULL
790 : };
791 :
792 0 : OUString sLocaleString( _rLocaleString );
793 0 : sal_Char nCompareTermination = 0;
794 :
795 0 : if ( _bAcceptCountryMismatch )
796 : {
797 : // strip the country part from the compare string
798 0 : sal_Int32 nCountrySep = sLocaleString.indexOf( '-' );
799 0 : if ( nCountrySep > -1 )
800 0 : sLocaleString = sLocaleString.copy( 0, nCountrySep );
801 :
802 : // the entries in the translation table are compared until the
803 : // - character only, not until the terminating 0
804 0 : nCompareTermination = '-';
805 : }
806 :
807 0 : const sal_Char** pLookup = pTranslations;
808 0 : for ( ; *pLookup; pLookup +=2 )
809 : {
810 0 : sal_Int32 nCompareUntil = 0;
811 0 : while ( (*pLookup)[ nCompareUntil ] != nCompareTermination && (*pLookup)[ nCompareUntil ] != 0 )
812 0 : ++nCompareUntil;
813 :
814 0 : if ( sLocaleString.equalsAsciiL( *pLookup, nCompareUntil ) )
815 0 : return *( pLookup + 1 );
816 : }
817 :
818 0 : if ( !_bAcceptCountryMismatch )
819 : // second round, this time without matching the country
820 0 : return lcl_getCollationForLocale( _rLocaleString, true );
821 :
822 : OSL_FAIL( "lcl_getCollationForLocale: unknown locale string, falling back to Latin1_General!" );
823 0 : return "Latin1_General";
824 : }
825 :
826 :
827 0 : OUString lcl_getSystemLocale( const Reference< XComponentContext >& _rxContext )
828 : {
829 0 : OUString sLocaleString = "en-US";
830 : try
831 : {
832 :
833 : Reference< XMultiServiceFactory > xConfigProvider(
834 0 : com::sun::star::configuration::theDefaultProvider::get( _rxContext ) );
835 :
836 :
837 : // arguments for creating the config access
838 0 : Sequence< Any > aArguments(2);
839 : // the path to the node to open
840 0 : OUString sNodePath("/org.openoffice.Setup/L10N" );
841 0 : aArguments[0] <<= PropertyValue( OUString("nodepath"), 0,
842 : makeAny( sNodePath ), PropertyState_DIRECT_VALUE
843 0 : );
844 : // the depth: -1 means unlimited
845 0 : aArguments[1] <<= PropertyValue(
846 : OUString("depth"), 0,
847 : makeAny( (sal_Int32)-1 ), PropertyState_DIRECT_VALUE
848 0 : );
849 :
850 :
851 : // create the access
852 : Reference< XPropertySet > xNode(
853 0 : xConfigProvider->createInstanceWithArguments(
854 : OUString("com.sun.star.configuration.ConfigurationAccess"),
855 0 : aArguments ),
856 0 : UNO_QUERY );
857 : OSL_ENSURE( xNode.is(), "lcl_getSystemLocale: invalid access returned (should throw an exception instead)!" );
858 :
859 :
860 : // ask for the system locale setting
861 0 : if ( xNode.is() )
862 0 : xNode->getPropertyValue("ooSetupSystemLocale") >>= sLocaleString;
863 : }
864 0 : catch( const Exception& )
865 : {
866 : OSL_FAIL( "lcl_getSystemLocale: caught an exception!" );
867 : }
868 0 : if ( sLocaleString.isEmpty() )
869 : {
870 0 : rtl_Locale* pProcessLocale = NULL;
871 0 : osl_getProcessLocale( &pProcessLocale );
872 0 : sLocaleString = LanguageTag( *pProcessLocale).getBcp47();
873 : }
874 0 : return sLocaleString;
875 : }
876 : }
877 :
878 0 : void ODriverDelegator::onConnectedNewDatabase( const Reference< XConnection >& _rxConnection )
879 : {
880 : try
881 : {
882 0 : Reference< XStatement > xStatement = _rxConnection->createStatement();
883 : OSL_ENSURE( xStatement.is(), "ODriverDelegator::onConnectedNewDatabase: could not create a statement!" );
884 0 : if ( xStatement.is() )
885 : {
886 0 : OUStringBuffer aStatement;
887 0 : aStatement.appendAscii( "SET DATABASE COLLATION \"" );
888 0 : aStatement.appendAscii( lcl_getCollationForLocale( lcl_getSystemLocale( m_xContext ) ) );
889 0 : aStatement.appendAscii( "\"" );
890 :
891 0 : xStatement->execute( aStatement.makeStringAndClear() );
892 0 : }
893 : }
894 0 : catch( const Exception& )
895 : {
896 : OSL_FAIL( "ODriverDelegator::onConnectedNewDatabase: caught an exception!" );
897 : }
898 0 : }
899 :
900 :
901 :
902 :
903 : } // namespace connectivity
904 :
905 :
906 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|