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