1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
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>
28 #include <cppuhelper/basemutex.hxx>
29 #include <comphelper/interfacecontainer3.hxx>
30 #include <cppuhelper/implbase.hxx>
31 #include <osl/diagnose.h>
32 #include <unotools/pathoptions.hxx>
33 #include <tools/urlobj.hxx>
34 #include <unotools/confignode.hxx>
36 #include "databaseregistrations.hxx"
40 using ::com::sun::star::uno::Reference
;
41 using ::com::sun::star::uno::RuntimeException
;
42 using ::com::sun::star::uno::Any
;
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
;
53 constexpr OUString CONF_ROOT_PATH
= u
"org.openoffice.Office.DataAccess/RegisteredNames"_ustr
;
54 constexpr OUString LOCATION
= u
"Location"_ustr
;
55 constexpr OUString NAME
= u
"Name"_ustr
;
57 // DatabaseRegistrations - declaration
58 typedef ::cppu::WeakImplHelper
< XDatabaseRegistrations
59 > DatabaseRegistrations_Base
;
63 class DatabaseRegistrations
:public ::cppu::BaseMutex
64 ,public DatabaseRegistrations_Base
67 explicit DatabaseRegistrations( const Reference
<XComponentContext
>& _rxContext
);
70 virtual ~DatabaseRegistrations() override
;
73 virtual sal_Bool SAL_CALL
hasRegisteredDatabase( const OUString
& Name
) override
;
74 virtual Sequence
< OUString
> SAL_CALL
getRegistrationNames() override
;
75 virtual OUString SAL_CALL
getDatabaseLocation( const OUString
& Name
) override
;
76 virtual void SAL_CALL
registerDatabaseLocation( const OUString
& Name
, const OUString
& Location
) override
;
77 virtual void SAL_CALL
revokeDatabaseLocation( const OUString
& Name
) override
;
78 virtual void SAL_CALL
changeDatabaseLocation( const OUString
& Name
, const OUString
& NewLocation
) override
;
79 virtual sal_Bool SAL_CALL
isDatabaseRegistrationReadOnly( const OUString
& Name
) override
;
80 virtual void SAL_CALL
addDatabaseRegistrationsListener( const Reference
< XDatabaseRegistrationsListener
>& Listener
) override
;
81 virtual void SAL_CALL
removeDatabaseRegistrationsListener( const Reference
< XDatabaseRegistrationsListener
>& Listener
) override
;
85 impl_checkValidName_common(std::u16string_view _rName
);
86 ::utl::OConfigurationNode
87 impl_checkValidName_throw_must_exist(const OUString
& _rName
);
88 ::utl::OConfigurationNode
89 impl_checkValidName_throw_must_not_exist(const OUString
& _rName
);
91 void impl_checkValidLocation_throw( std::u16string_view _rLocation
);
93 /** retrieves the configuration node whose "Name" sub node has the given value
95 Since we separated the name of the registration node from the "Name" value of the registration, we cannot
96 simply do a "getByName" (equivalent) when we want to retrieve the node for a given registration name.
97 Instead, we must search all nodes.
99 If a node with the given display name does not exist, then a NoSuchElementException is thrown.
101 If no exception is thrown, then a valid node is returned: If the node existed it is returned.
103 ::utl::OConfigurationNode
104 impl_getNodeForName_throw_must_exist(const OUString
& _rName
);
106 /** retrieves the configuration node whose "Name" sub node has the given value
108 Since we separated the name of the registration node from the "Name" value of the registration, we cannot
109 simply do a "getByName" (equivalent) when we want to retrieve the node for a given registration name.
110 Instead, we must search all nodes.
112 If a node with the given name already exists, then an ElementExistException is thrown.
114 If no exception is thrown, then a valid node is returned: If the node did not yet exist a new node is created,
115 in this case the root node is not yet committed.
117 ::utl::OConfigurationNode
118 impl_getNodeForName_throw_must_not_exist(const OUString
& _rName
);
121 ::utl::OConfigurationNode
122 impl_getNodeForName_nothrow(std::u16string_view _rName
);
125 Reference
<XComponentContext
> m_aContext
;
126 ::utl::OConfigurationTreeRoot m_aConfigurationRoot
;
127 ::comphelper::OInterfaceContainerHelper3
<XDatabaseRegistrationsListener
> m_aRegistrationListeners
;
132 // DatabaseRegistrations - implementation
133 DatabaseRegistrations::DatabaseRegistrations( const Reference
<XComponentContext
> & _rxContext
)
134 :m_aContext( _rxContext
)
135 ,m_aRegistrationListeners( m_aMutex
)
137 m_aConfigurationRoot
= ::utl::OConfigurationTreeRoot::createWithComponentContext(
138 m_aContext
, CONF_ROOT_PATH
);
141 DatabaseRegistrations::~DatabaseRegistrations()
145 ::utl::OConfigurationNode
DatabaseRegistrations::impl_getNodeForName_nothrow( std::u16string_view _rName
)
147 const Sequence
< OUString
> aNames( m_aConfigurationRoot
.getNodeNames() );
148 for ( auto const & nodeName
: aNames
)
150 ::utl::OConfigurationNode aNodeForName
= m_aConfigurationRoot
.openNode( nodeName
);
153 OSL_VERIFY( aNodeForName
.getNodeValue( NAME
) >>= sTestName
);
154 if ( sTestName
== _rName
)
157 return ::utl::OConfigurationNode();
160 ::utl::OConfigurationNode
DatabaseRegistrations::impl_getNodeForName_throw_must_exist(const OUString
& _rName
)
162 ::utl::OConfigurationNode
aNodeForName( impl_getNodeForName_nothrow( _rName
) );
164 if (!aNodeForName
.isValid())
166 throw NoSuchElementException( _rName
, *this );
172 ::utl::OConfigurationNode
DatabaseRegistrations::impl_getNodeForName_throw_must_not_exist(const OUString
& _rName
)
174 ::utl::OConfigurationNode
aNodeForName( impl_getNodeForName_nothrow( _rName
) );
176 if (aNodeForName
.isValid())
177 throw ElementExistException( _rName
, *this );
180 OUString sNewNodeName
= "org.openoffice." + _rName
;
181 while ( m_aConfigurationRoot
.hasByName( sNewNodeName
) )
183 sNewNodeName
= "org.openoffice." + _rName
+ " 2";
186 ::utl::OConfigurationNode
aNewNode( m_aConfigurationRoot
.createNode( sNewNodeName
) );
187 aNewNode
.setNodeValue( NAME
, Any( _rName
) );
191 void DatabaseRegistrations::impl_checkValidName_common(std::u16string_view _rName
)
193 if ( !m_aConfigurationRoot
.isValid() )
194 throw RuntimeException( OUString(), *this );
196 if ( _rName
.empty() )
197 throw IllegalArgumentException( OUString(), *this, 1 );
200 ::utl::OConfigurationNode
DatabaseRegistrations::impl_checkValidName_throw_must_exist(const OUString
& _rName
)
202 impl_checkValidName_common(_rName
);
203 return impl_getNodeForName_throw_must_exist(_rName
);
206 ::utl::OConfigurationNode
DatabaseRegistrations::impl_checkValidName_throw_must_not_exist(const OUString
& _rName
)
208 impl_checkValidName_common(_rName
);
209 return impl_getNodeForName_throw_must_not_exist(_rName
);
212 void DatabaseRegistrations::impl_checkValidLocation_throw( std::u16string_view _rLocation
)
214 if ( _rLocation
.empty() )
215 throw IllegalArgumentException( OUString(), *this, 2 );
217 INetURLObject
aURL( _rLocation
);
218 if ( aURL
.GetProtocol() == INetProtocol::NotValid
)
219 throw IllegalArgumentException( OUString(), *this, 2 );
222 sal_Bool SAL_CALL
DatabaseRegistrations::hasRegisteredDatabase( const OUString
& Name
)
224 ::osl::MutexGuard
aGuard( m_aMutex
);
225 ::utl::OConfigurationNode aNodeForName
= impl_getNodeForName_nothrow( Name
);
226 return aNodeForName
.isValid();
229 Sequence
< OUString
> SAL_CALL
DatabaseRegistrations::getRegistrationNames()
231 ::osl::MutexGuard
aGuard( m_aMutex
);
232 if ( !m_aConfigurationRoot
.isValid() )
233 throw RuntimeException( OUString(), *this );
235 const Sequence
< OUString
> aProgrammaticNames( m_aConfigurationRoot
.getNodeNames() );
236 Sequence
< OUString
> aDisplayNames( aProgrammaticNames
.getLength() );
237 OUString
* pDisplayName
= aDisplayNames
.getArray();
239 for ( auto const & name
: aProgrammaticNames
)
241 ::utl::OConfigurationNode aRegistrationNode
= m_aConfigurationRoot
.openNode( name
);
242 OSL_VERIFY( aRegistrationNode
.getNodeValue( NAME
) >>= *pDisplayName
);
246 return aDisplayNames
;
249 OUString SAL_CALL
DatabaseRegistrations::getDatabaseLocation( const OUString
& Name
)
251 ::osl::MutexGuard
aGuard( m_aMutex
);
253 ::utl::OConfigurationNode aNodeForName
= impl_checkValidName_throw_must_exist(Name
);
256 OSL_VERIFY( aNodeForName
.getNodeValue( LOCATION
) >>= sLocation
);
257 sLocation
= SvtPathOptions().SubstituteVariable( sLocation
);
262 void SAL_CALL
DatabaseRegistrations::registerDatabaseLocation( const OUString
& Name
, const OUString
& Location
)
264 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
267 impl_checkValidLocation_throw( Location
);
268 ::utl::OConfigurationNode aDataSourceRegistration
= impl_checkValidName_throw_must_not_exist(Name
);
271 aDataSourceRegistration
.setNodeValue( LOCATION
, Any( Location
) );
272 m_aConfigurationRoot
.commit();
275 DatabaseRegistrationEvent
aEvent( *this, Name
, OUString(), Location
);
277 m_aRegistrationListeners
.notifyEach( &XDatabaseRegistrationsListener::registeredDatabaseLocation
, aEvent
);
280 void SAL_CALL
DatabaseRegistrations::revokeDatabaseLocation( const OUString
& Name
)
282 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
285 ::utl::OConfigurationNode aNodeForName
= impl_checkValidName_throw_must_exist(Name
);
287 // obtain properties for notification
289 OSL_VERIFY( aNodeForName
.getNodeValue( LOCATION
) >>= sLocation
);
292 if ( aNodeForName
.isReadonly()
293 || !m_aConfigurationRoot
.removeNode( aNodeForName
.getLocalName() )
295 throw IllegalAccessException( OUString(), *this );
297 m_aConfigurationRoot
.commit();
300 DatabaseRegistrationEvent
aEvent( *this, Name
, sLocation
, OUString() );
302 m_aRegistrationListeners
.notifyEach( &XDatabaseRegistrationsListener::revokedDatabaseLocation
, aEvent
);
305 void SAL_CALL
DatabaseRegistrations::changeDatabaseLocation( const OUString
& Name
, const OUString
& NewLocation
)
307 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
310 impl_checkValidLocation_throw( NewLocation
);
311 ::utl::OConfigurationNode aDataSourceRegistration
= impl_checkValidName_throw_must_exist(Name
);
313 if ( aDataSourceRegistration
.isReadonly() )
314 throw IllegalAccessException( OUString(), *this );
316 // obtain properties for notification
317 OUString sOldLocation
;
318 OSL_VERIFY( aDataSourceRegistration
.getNodeValue( LOCATION
) >>= sOldLocation
);
321 aDataSourceRegistration
.setNodeValue( LOCATION
, Any( NewLocation
) );
322 m_aConfigurationRoot
.commit();
325 DatabaseRegistrationEvent
aEvent( *this, Name
, sOldLocation
, NewLocation
);
327 m_aRegistrationListeners
.notifyEach( &XDatabaseRegistrationsListener::changedDatabaseLocation
, aEvent
);
330 sal_Bool SAL_CALL
DatabaseRegistrations::isDatabaseRegistrationReadOnly( const OUString
& Name
)
332 ::osl::MutexGuard
aGuard( m_aMutex
);
333 ::utl::OConfigurationNode aDataSourceRegistration
= impl_checkValidName_throw_must_exist(Name
);
334 return aDataSourceRegistration
.isReadonly();
337 void SAL_CALL
DatabaseRegistrations::addDatabaseRegistrationsListener( const Reference
< XDatabaseRegistrationsListener
>& Listener
)
340 m_aRegistrationListeners
.addInterface( Listener
);
343 void SAL_CALL
DatabaseRegistrations::removeDatabaseRegistrationsListener( const Reference
< XDatabaseRegistrationsListener
>& Listener
)
346 m_aRegistrationListeners
.removeInterface( Listener
);
349 // DatabaseRegistrations - factory
350 Reference
< XDatabaseRegistrations
> createDataSourceRegistrations( const Reference
<XComponentContext
> & _rxContext
)
352 return new DatabaseRegistrations( _rxContext
);
355 } // namespace dbaccess
357 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */