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