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