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