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