1 /************************************************************************* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * Copyright 2000, 2010 Oracle and/or its affiliates. 5 * 6 * OpenOffice.org - a multi-platform office productivity suite 7 * 8 * This file is part of OpenOffice.org. 9 * 10 * OpenOffice.org is free software: you can redistribute it and/or modify 11 * it under the terms of the GNU Lesser General Public License version 3 12 * only, as published by the Free Software Foundation. 13 * 14 * OpenOffice.org is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Lesser General Public License version 3 for more details 18 * (a copy is included in the LICENSE file that accompanied this code). 19 * 20 * You should have received a copy of the GNU Lesser General Public License 21 * version 3 along with OpenOffice.org. If not, see 22 * <http://www.openoffice.org/license.html> 23 * for a copy of the LGPLv3 License. 24 * 25 ************************************************************************/ 26 27 // MARKER(update_precomp.py): autogen include statement, do not remove 28 #include "precompiled_dbaccess.hxx" 29 30 /** === begin UNO includes === **/ 31 #include <com/sun/star/sdb/XDatabaseRegistrations.hpp> 32 /** === end UNO includes === **/ 33 34 #include <comphelper/componentcontext.hxx> 35 #include <cppuhelper/basemutex.hxx> 36 #include <cppuhelper/interfacecontainer.hxx> 37 #include <cppuhelper/implbase1.hxx> 38 #include <rtl/ustrbuf.hxx> 39 #include <unotools/pathoptions.hxx> 40 #include <tools/urlobj.hxx> 41 #include <unotools/confignode.hxx> 42 43 //........................................................................ 44 namespace dbaccess 45 { 46 //........................................................................ 47 48 /** === begin UNO using === **/ 49 using ::com::sun::star::uno::Reference; 50 using ::com::sun::star::uno::XInterface; 51 using ::com::sun::star::uno::UNO_QUERY; 52 using ::com::sun::star::uno::UNO_QUERY_THROW; 53 using ::com::sun::star::uno::UNO_SET_THROW; 54 using ::com::sun::star::uno::Exception; 55 using ::com::sun::star::uno::RuntimeException; 56 using ::com::sun::star::uno::Any; 57 using ::com::sun::star::uno::makeAny; 58 using ::com::sun::star::uno::Sequence; 59 using ::com::sun::star::uno::Type; 60 using ::com::sun::star::container::NoSuchElementException; 61 using ::com::sun::star::lang::IllegalArgumentException; 62 using ::com::sun::star::lang::IllegalAccessException; 63 using ::com::sun::star::container::ElementExistException; 64 using ::com::sun::star::sdb::XDatabaseRegistrations; 65 using ::com::sun::star::sdb::XDatabaseRegistrationsListener; 66 using ::com::sun::star::sdb::DatabaseRegistrationEvent; 67 using ::com::sun::star::uno::XAggregation; 68 /** === end UNO using === **/ 69 70 //-------------------------------------------------------------------- 71 static const ::rtl::OUString& getConfigurationRootPath() 72 { 73 static ::rtl::OUString s_sNodeName = ::rtl::OUString::createFromAscii("org.openoffice.Office.DataAccess/RegisteredNames"); 74 return s_sNodeName; 75 } 76 77 //-------------------------------------------------------------------- 78 const ::rtl::OUString& getLocationNodeName() 79 { 80 static ::rtl::OUString s_sNodeName = ::rtl::OUString::createFromAscii( "Location" ); 81 return s_sNodeName; 82 } 83 84 //-------------------------------------------------------------------- 85 const ::rtl::OUString& getNameNodeName() 86 { 87 static ::rtl::OUString s_sNodeName = ::rtl::OUString::createFromAscii( "Name" ); 88 return s_sNodeName; 89 } 90 91 //==================================================================== 92 //= DatabaseRegistrations - declaration 93 //==================================================================== 94 typedef ::cppu::WeakAggImplHelper1 < XDatabaseRegistrations 95 > DatabaseRegistrations_Base; 96 class DatabaseRegistrations :public ::cppu::BaseMutex 97 ,public DatabaseRegistrations_Base 98 { 99 public: 100 DatabaseRegistrations( const ::comphelper::ComponentContext& _rxContext ); 101 102 protected: 103 ~DatabaseRegistrations(); 104 105 public: 106 virtual ::sal_Bool SAL_CALL hasRegisteredDatabase( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, RuntimeException); 107 virtual Sequence< ::rtl::OUString > SAL_CALL getRegistrationNames() throw (RuntimeException); 108 virtual ::rtl::OUString SAL_CALL getDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException); 109 virtual void SAL_CALL registerDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _Location ) throw (IllegalArgumentException, ElementExistException, RuntimeException); 110 virtual void SAL_CALL revokeDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException); 111 virtual void SAL_CALL changeDatabaseLocation( const ::rtl::OUString& Name, const ::rtl::OUString& NewLocation ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException); 112 virtual ::sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException); 113 virtual void SAL_CALL addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) throw (RuntimeException); 114 virtual void SAL_CALL removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) throw (RuntimeException); 115 116 private: 117 ::utl::OConfigurationNode 118 impl_checkValidName_throw( const ::rtl::OUString& _rName, const bool _bMustExist ); 119 120 void impl_checkValidLocation_throw( const ::rtl::OUString& _rLocation ); 121 122 /** retrieves the configuration node whose "Name" sub node has the given value 123 124 Since we separated the name of the registration node from the "Name" value of the registration, we cannot 125 simply do a "getByName" (equivalent) when we want to retrieve the node for a given registration name. 126 Instead, we must search all nodes. 127 128 If _bMustExist is <TRUE/>, and a node with the given display name does not exist, then a NoSuchElementException 129 is thrown. 130 131 If _bMustExist is <FALSE/>, and a node with the given name already exists, then a ElementExistException is 132 thrown. 133 134 In either case, if no exception is thrown, then a valid node is returned: If the node existed and was allowed 135 to exist, it is returned, if the node did not yet exist, and was required to not exist, a new node is created. 136 However, in this case the root node is not yet committed. 137 */ 138 ::utl::OConfigurationNode 139 impl_getNodeForName_throw( const ::rtl::OUString& _rName, const bool _bMustExist ); 140 141 ::utl::OConfigurationNode 142 impl_getNodeForName_nothrow( const ::rtl::OUString& _rName ); 143 144 private: 145 ::comphelper::ComponentContext m_aContext; 146 ::utl::OConfigurationTreeRoot m_aConfigurationRoot; 147 ::cppu::OInterfaceContainerHelper m_aRegistrationListeners; 148 }; 149 150 //==================================================================== 151 //= DatabaseRegistrations - implementation 152 //==================================================================== 153 //-------------------------------------------------------------------- 154 DatabaseRegistrations::DatabaseRegistrations( const ::comphelper::ComponentContext& _rxContext ) 155 :m_aContext( _rxContext ) 156 ,m_aConfigurationRoot() 157 ,m_aRegistrationListeners( m_aMutex ) 158 { 159 m_aConfigurationRoot = ::utl::OConfigurationTreeRoot::createWithServiceFactory( 160 m_aContext.getLegacyServiceFactory(), getConfigurationRootPath(), -1, ::utl::OConfigurationTreeRoot::CM_UPDATABLE ); 161 } 162 163 //-------------------------------------------------------------------- 164 DatabaseRegistrations::~DatabaseRegistrations() 165 { 166 } 167 168 //-------------------------------------------------------------------- 169 ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_nothrow( const ::rtl::OUString& _rName ) 170 { 171 Sequence< ::rtl::OUString > aNames( m_aConfigurationRoot.getNodeNames() ); 172 for ( const ::rtl::OUString* pName = aNames.getConstArray(); 173 pName != aNames.getConstArray() + aNames.getLength(); 174 ++pName 175 ) 176 { 177 ::utl::OConfigurationNode aNodeForName = m_aConfigurationRoot.openNode( *pName ); 178 179 ::rtl::OUString sTestName; 180 OSL_VERIFY( aNodeForName.getNodeValue( getNameNodeName() ) >>= sTestName ); 181 if ( sTestName == _rName ) 182 return aNodeForName; 183 } 184 return ::utl::OConfigurationNode(); 185 } 186 187 //-------------------------------------------------------------------- 188 ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_throw( const ::rtl::OUString& _rName, const bool _bMustExist ) 189 { 190 ::utl::OConfigurationNode aNodeForName( impl_getNodeForName_nothrow( _rName ) ); 191 192 if ( aNodeForName.isValid() ) 193 { 194 if ( !_bMustExist ) 195 throw ElementExistException( _rName, *this ); 196 197 return aNodeForName; 198 } 199 200 if ( _bMustExist ) 201 throw NoSuchElementException( _rName, *this ); 202 203 ::rtl::OUString sNewNodeName; 204 { 205 ::rtl::OUStringBuffer aNewNodeName; 206 aNewNodeName.appendAscii( "org.openoffice." ); 207 aNewNodeName.append( _rName ); 208 209 // make unique 210 ::rtl::OUStringBuffer aReset( aNewNodeName ); 211 sNewNodeName = aNewNodeName.makeStringAndClear(); 212 sal_Int32 i=2; 213 while ( m_aConfigurationRoot.hasByName( sNewNodeName ) ) 214 { 215 aNewNodeName = aReset; 216 aNewNodeName.appendAscii( " " ); 217 aNewNodeName.append( i ); 218 sNewNodeName = aNewNodeName.makeStringAndClear(); 219 } 220 } 221 222 ::utl::OConfigurationNode aNewNode( m_aConfigurationRoot.createNode( sNewNodeName ) ); 223 aNewNode.setNodeValue( getNameNodeName(), makeAny( _rName ) ); 224 return aNewNode; 225 } 226 227 //-------------------------------------------------------------------- 228 ::utl::OConfigurationNode DatabaseRegistrations::impl_checkValidName_throw( const ::rtl::OUString& _rName, const bool _bMustExist ) 229 { 230 if ( !m_aConfigurationRoot.isValid() ) 231 throw RuntimeException( ::rtl::OUString(), *this ); 232 233 if ( !_rName.getLength() ) 234 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); 235 236 return impl_getNodeForName_throw( _rName, _bMustExist ); 237 } 238 239 //-------------------------------------------------------------------- 240 void DatabaseRegistrations::impl_checkValidLocation_throw( const ::rtl::OUString& _rLocation ) 241 { 242 if ( !_rLocation.getLength() ) 243 throw IllegalArgumentException( ::rtl::OUString(), *this, 2 ); 244 245 INetURLObject aURL( _rLocation ); 246 if ( aURL.GetProtocol() == INET_PROT_NOT_VALID ) 247 throw IllegalArgumentException( ::rtl::OUString(), *this, 2 ); 248 } 249 250 //-------------------------------------------------------------------- 251 ::sal_Bool SAL_CALL DatabaseRegistrations::hasRegisteredDatabase( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, RuntimeException) 252 { 253 ::osl::MutexGuard aGuard( m_aMutex ); 254 ::utl::OConfigurationNode aNodeForName = impl_getNodeForName_nothrow( _Name ); 255 return aNodeForName.isValid(); 256 } 257 258 //------------------------------------------------------------------------------ 259 Sequence< ::rtl::OUString > SAL_CALL DatabaseRegistrations::getRegistrationNames() throw (RuntimeException) 260 { 261 ::osl::MutexGuard aGuard( m_aMutex ); 262 if ( !m_aConfigurationRoot.isValid() ) 263 throw RuntimeException( ::rtl::OUString(), *this ); 264 265 Sequence< ::rtl::OUString > aProgrammaticNames( m_aConfigurationRoot.getNodeNames() ); 266 Sequence< ::rtl::OUString > aDisplayNames( aProgrammaticNames.getLength() ); 267 ::rtl::OUString* pDisplayName = aDisplayNames.getArray(); 268 269 for ( const ::rtl::OUString* pName = aProgrammaticNames.getConstArray(); 270 pName != aProgrammaticNames.getConstArray() + aProgrammaticNames.getLength(); 271 ++pName, ++pDisplayName 272 ) 273 { 274 ::utl::OConfigurationNode aRegistrationNode = m_aConfigurationRoot.openNode( *pName ); 275 OSL_VERIFY( aRegistrationNode.getNodeValue( getNameNodeName() ) >>= *pDisplayName ); 276 277 } 278 279 return aDisplayNames; 280 } 281 282 //-------------------------------------------------------------------- 283 ::rtl::OUString SAL_CALL DatabaseRegistrations::getDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException) 284 { 285 ::osl::MutexGuard aGuard( m_aMutex ); 286 287 ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw( _Name, true ); 288 289 ::rtl::OUString sLocation; 290 OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation ); 291 sLocation = SvtPathOptions().SubstituteVariable( sLocation ); 292 293 return sLocation; 294 } 295 296 //-------------------------------------------------------------------- 297 void SAL_CALL DatabaseRegistrations::registerDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _Location ) throw (IllegalArgumentException, ElementExistException, RuntimeException) 298 { 299 ::osl::ClearableMutexGuard aGuard( m_aMutex ); 300 301 // check 302 impl_checkValidLocation_throw( _Location ); 303 ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw( _Name, false ); 304 305 // register 306 aDataSourceRegistration.setNodeValue( getLocationNodeName(), makeAny( _Location ) ); 307 m_aConfigurationRoot.commit(); 308 309 // notify 310 DatabaseRegistrationEvent aEvent( *this, _Name, ::rtl::OUString(), _Location ); 311 aGuard.clear(); 312 m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::registeredDatabaseLocation, aEvent ); 313 } 314 315 //-------------------------------------------------------------------- 316 void SAL_CALL DatabaseRegistrations::revokeDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException) 317 { 318 ::osl::ClearableMutexGuard aGuard( m_aMutex ); 319 320 // check 321 ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw( _Name, true ); 322 323 // obtain properties for notification 324 ::rtl::OUString sLocation; 325 OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation ); 326 327 // revoke 328 if ( aNodeForName.isReadonly() 329 || !m_aConfigurationRoot.removeNode( aNodeForName.getLocalName() ) 330 ) 331 throw IllegalAccessException( ::rtl::OUString(), *this ); 332 333 m_aConfigurationRoot.commit(); 334 335 // notify 336 DatabaseRegistrationEvent aEvent( *this, _Name, sLocation, ::rtl::OUString() ); 337 aGuard.clear(); 338 m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::revokedDatabaseLocation, aEvent ); 339 } 340 341 //-------------------------------------------------------------------- 342 void SAL_CALL DatabaseRegistrations::changeDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _NewLocation ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException) 343 { 344 ::osl::ClearableMutexGuard aGuard( m_aMutex ); 345 346 // check 347 impl_checkValidLocation_throw( _NewLocation ); 348 ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw( _Name, true ); 349 350 if ( aDataSourceRegistration.isReadonly() ) 351 throw IllegalAccessException( ::rtl::OUString(), *this ); 352 353 // obtain properties for notification 354 ::rtl::OUString sOldLocation; 355 OSL_VERIFY( aDataSourceRegistration.getNodeValue( getLocationNodeName() ) >>= sOldLocation ); 356 357 // change 358 aDataSourceRegistration.setNodeValue( getLocationNodeName(), makeAny( _NewLocation ) ); 359 m_aConfigurationRoot.commit(); 360 361 // notify 362 DatabaseRegistrationEvent aEvent( *this, _Name, sOldLocation, _NewLocation ); 363 aGuard.clear(); 364 m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::changedDatabaseLocation, aEvent ); 365 } 366 367 //-------------------------------------------------------------------- 368 ::sal_Bool SAL_CALL DatabaseRegistrations::isDatabaseRegistrationReadOnly( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException) 369 { 370 ::osl::MutexGuard aGuard( m_aMutex ); 371 ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw( _Name, true ); 372 return aDataSourceRegistration.isReadonly(); 373 } 374 375 //-------------------------------------------------------------------- 376 void SAL_CALL DatabaseRegistrations::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException) 377 { 378 if ( _Listener.is() ) 379 m_aRegistrationListeners.addInterface( _Listener ); 380 } 381 382 //-------------------------------------------------------------------- 383 void SAL_CALL DatabaseRegistrations::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException) 384 { 385 if ( _Listener.is() ) 386 m_aRegistrationListeners.removeInterface( _Listener ); 387 } 388 389 //==================================================================== 390 //= DatabaseRegistrations - factory 391 //==================================================================== 392 Reference< XAggregation > createDataSourceRegistrations( const ::comphelper::ComponentContext& _rxContext ) 393 { 394 return new DatabaseRegistrations( _rxContext ); 395 } 396 397 //........................................................................ 398 } // namespace dbaccess 399 //........................................................................ 400