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