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