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 20 : static OUString getConfigurationRootPath()
56 : {
57 20 : return OUString("org.openoffice.Office.DataAccess/RegisteredNames");
58 : }
59 :
60 323 : static OUString getLocationNodeName()
61 : {
62 323 : return OUString("Location");
63 : }
64 :
65 872 : static OUString getNameNodeName()
66 : {
67 872 : return OUString("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 : DatabaseRegistrations( const Reference<XComponentContext>& _rxContext );
78 :
79 : protected:
80 : virtual ~DatabaseRegistrations();
81 :
82 : public:
83 : virtual sal_Bool SAL_CALL hasRegisteredDatabase( const OUString& _Name ) throw (IllegalArgumentException, RuntimeException, std::exception) SAL_OVERRIDE;
84 : virtual Sequence< OUString > SAL_CALL getRegistrationNames() throw (RuntimeException, std::exception) SAL_OVERRIDE;
85 : virtual OUString SAL_CALL getDatabaseLocation( const OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException, std::exception) SAL_OVERRIDE;
86 : virtual void SAL_CALL registerDatabaseLocation( const OUString& _Name, const OUString& _Location ) throw (IllegalArgumentException, ElementExistException, RuntimeException, std::exception) SAL_OVERRIDE;
87 : virtual void SAL_CALL revokeDatabaseLocation( const OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException, std::exception) SAL_OVERRIDE;
88 : virtual void SAL_CALL changeDatabaseLocation( const OUString& Name, const OUString& NewLocation ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException, std::exception) SAL_OVERRIDE;
89 : virtual sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException, std::exception) SAL_OVERRIDE;
90 : virtual void SAL_CALL addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
91 : virtual void SAL_CALL removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) throw (RuntimeException, std::exception) SAL_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 a 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 : ::cppu::OInterfaceContainerHelper m_aRegistrationListeners;
138 : };
139 :
140 : // DatabaseRegistrations - implementation
141 20 : DatabaseRegistrations::DatabaseRegistrations( const Reference<XComponentContext> & _rxContext )
142 : :m_aContext( _rxContext )
143 : ,m_aConfigurationRoot()
144 20 : ,m_aRegistrationListeners( m_aMutex )
145 : {
146 40 : m_aConfigurationRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext(
147 20 : m_aContext, getConfigurationRootPath(), -1, ::utl::OConfigurationTreeRoot::CM_UPDATABLE );
148 20 : }
149 :
150 32 : DatabaseRegistrations::~DatabaseRegistrations()
151 : {
152 32 : }
153 :
154 489 : ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_nothrow( const OUString& _rName )
155 : {
156 489 : Sequence< OUString > aNames( m_aConfigurationRoot.getNodeNames() );
157 1928 : for ( const OUString* pName = aNames.getConstArray();
158 964 : pName != aNames.getConstArray() + aNames.getLength();
159 : ++pName
160 : )
161 : {
162 780 : ::utl::OConfigurationNode aNodeForName = m_aConfigurationRoot.openNode( *pName );
163 :
164 1255 : OUString sTestName;
165 780 : OSL_VERIFY( aNodeForName.getNodeValue( getNameNodeName() ) >>= sTestName );
166 780 : if ( sTestName == _rName )
167 305 : return aNodeForName;
168 475 : }
169 184 : return ::utl::OConfigurationNode();
170 : }
171 :
172 321 : ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_throw_must_exist(const OUString& _rName)
173 : {
174 321 : ::utl::OConfigurationNode aNodeForName( impl_getNodeForName_nothrow( _rName ) );
175 :
176 321 : if (!aNodeForName.isValid())
177 : {
178 86 : throw NoSuchElementException( _rName, *this );
179 : }
180 :
181 235 : return aNodeForName;
182 : }
183 :
184 88 : ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_throw_must_not_exist(const OUString& _rName)
185 : {
186 88 : ::utl::OConfigurationNode aNodeForName( impl_getNodeForName_nothrow( _rName ) );
187 :
188 88 : if (aNodeForName.isValid())
189 0 : throw ElementExistException( _rName, *this );
190 :
191 176 : OUString sNewNodeName;
192 : {
193 88 : OUStringBuffer aNewNodeName;
194 88 : aNewNodeName.appendAscii( "org.openoffice." );
195 88 : aNewNodeName.append( _rName );
196 :
197 : // make unique
198 176 : OUStringBuffer aReset( aNewNodeName );
199 88 : sNewNodeName = aNewNodeName.makeStringAndClear();
200 88 : sal_Int32 i=2;
201 176 : while ( m_aConfigurationRoot.hasByName( sNewNodeName ) )
202 : {
203 0 : aNewNodeName = aReset;
204 0 : aNewNodeName.appendAscii( " " );
205 0 : aNewNodeName.append( i );
206 0 : sNewNodeName = aNewNodeName.makeStringAndClear();
207 88 : }
208 : }
209 :
210 88 : ::utl::OConfigurationNode aNewNode( m_aConfigurationRoot.createNode( sNewNodeName ) );
211 88 : aNewNode.setNodeValue( getNameNodeName(), makeAny( _rName ) );
212 176 : return aNewNode;
213 : }
214 :
215 409 : void DatabaseRegistrations::impl_checkValidName_common(const OUString& _rName)
216 : {
217 409 : if ( !m_aConfigurationRoot.isValid() )
218 0 : throw RuntimeException( OUString(), *this );
219 :
220 409 : if ( _rName.isEmpty() )
221 0 : throw IllegalArgumentException( OUString(), *this, 1 );
222 409 : }
223 :
224 321 : ::utl::OConfigurationNode DatabaseRegistrations::impl_checkValidName_throw_must_exist(const OUString& _rName)
225 : {
226 321 : impl_checkValidName_common(_rName);
227 321 : return impl_getNodeForName_throw_must_exist(_rName);
228 : }
229 :
230 88 : ::utl::OConfigurationNode DatabaseRegistrations::impl_checkValidName_throw_must_not_exist(const OUString& _rName)
231 : {
232 88 : impl_checkValidName_common(_rName);
233 88 : return impl_getNodeForName_throw_must_not_exist(_rName);
234 : }
235 :
236 88 : void DatabaseRegistrations::impl_checkValidLocation_throw( const OUString& _rLocation )
237 : {
238 88 : if ( _rLocation.isEmpty() )
239 0 : throw IllegalArgumentException( OUString(), *this, 2 );
240 :
241 88 : INetURLObject aURL( _rLocation );
242 88 : if ( aURL.GetProtocol() == INetProtocol::NotValid )
243 0 : throw IllegalArgumentException( OUString(), *this, 2 );
244 88 : }
245 :
246 80 : sal_Bool SAL_CALL DatabaseRegistrations::hasRegisteredDatabase( const OUString& _Name ) throw (IllegalArgumentException, RuntimeException, std::exception)
247 : {
248 80 : ::osl::MutexGuard aGuard( m_aMutex );
249 160 : ::utl::OConfigurationNode aNodeForName = impl_getNodeForName_nothrow( _Name );
250 160 : return aNodeForName.isValid();
251 : }
252 :
253 4 : Sequence< OUString > SAL_CALL DatabaseRegistrations::getRegistrationNames() throw (RuntimeException, std::exception)
254 : {
255 4 : ::osl::MutexGuard aGuard( m_aMutex );
256 4 : if ( !m_aConfigurationRoot.isValid() )
257 0 : throw RuntimeException( OUString(), *this );
258 :
259 8 : Sequence< OUString > aProgrammaticNames( m_aConfigurationRoot.getNodeNames() );
260 4 : Sequence< OUString > aDisplayNames( aProgrammaticNames.getLength() );
261 4 : OUString* pDisplayName = aDisplayNames.getArray();
262 :
263 16 : for ( const OUString* pName = aProgrammaticNames.getConstArray();
264 8 : pName != aProgrammaticNames.getConstArray() + aProgrammaticNames.getLength();
265 : ++pName, ++pDisplayName
266 : )
267 : {
268 4 : ::utl::OConfigurationNode aRegistrationNode = m_aConfigurationRoot.openNode( *pName );
269 4 : OSL_VERIFY( aRegistrationNode.getNodeValue( getNameNodeName() ) >>= *pDisplayName );
270 4 : }
271 :
272 8 : return aDisplayNames;
273 : }
274 :
275 237 : OUString SAL_CALL DatabaseRegistrations::getDatabaseLocation( const OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException, std::exception)
276 : {
277 237 : ::osl::MutexGuard aGuard( m_aMutex );
278 :
279 388 : ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw_must_exist(_Name);
280 :
281 151 : OUString sLocation;
282 151 : OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation );
283 151 : sLocation = SvtPathOptions().SubstituteVariable( sLocation );
284 :
285 388 : return sLocation;
286 : }
287 :
288 88 : void SAL_CALL DatabaseRegistrations::registerDatabaseLocation( const OUString& _Name, const OUString& _Location ) throw (IllegalArgumentException, ElementExistException, RuntimeException, std::exception)
289 : {
290 88 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
291 :
292 : // check
293 88 : impl_checkValidLocation_throw( _Location );
294 176 : ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_not_exist(_Name);
295 :
296 : // register
297 88 : aDataSourceRegistration.setNodeValue( getLocationNodeName(), makeAny( _Location ) );
298 88 : m_aConfigurationRoot.commit();
299 :
300 : // notify
301 176 : DatabaseRegistrationEvent aEvent( *this, _Name, OUString(), _Location );
302 88 : aGuard.clear();
303 176 : m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::registeredDatabaseLocation, aEvent );
304 88 : }
305 :
306 84 : void SAL_CALL DatabaseRegistrations::revokeDatabaseLocation( const OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException, std::exception)
307 : {
308 84 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
309 :
310 : // check
311 168 : ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw_must_exist(_Name);
312 :
313 : // obtain properties for notification
314 168 : OUString sLocation;
315 84 : OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation );
316 :
317 : // revoke
318 252 : if ( aNodeForName.isReadonly()
319 336 : || !m_aConfigurationRoot.removeNode( aNodeForName.getLocalName() )
320 : )
321 0 : throw IllegalAccessException( OUString(), *this );
322 :
323 84 : m_aConfigurationRoot.commit();
324 :
325 : // notify
326 168 : DatabaseRegistrationEvent aEvent( *this, _Name, sLocation, OUString() );
327 84 : aGuard.clear();
328 168 : m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::revokedDatabaseLocation, aEvent );
329 84 : }
330 :
331 0 : void SAL_CALL DatabaseRegistrations::changeDatabaseLocation( const OUString& _Name, const OUString& _NewLocation ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException, std::exception)
332 : {
333 0 : ::osl::ClearableMutexGuard aGuard( m_aMutex );
334 :
335 : // check
336 0 : impl_checkValidLocation_throw( _NewLocation );
337 0 : ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_exist(_Name);
338 :
339 0 : if ( aDataSourceRegistration.isReadonly() )
340 0 : throw IllegalAccessException( OUString(), *this );
341 :
342 : // obtain properties for notification
343 0 : OUString sOldLocation;
344 0 : OSL_VERIFY( aDataSourceRegistration.getNodeValue( getLocationNodeName() ) >>= sOldLocation );
345 :
346 : // change
347 0 : aDataSourceRegistration.setNodeValue( getLocationNodeName(), makeAny( _NewLocation ) );
348 0 : m_aConfigurationRoot.commit();
349 :
350 : // notify
351 0 : DatabaseRegistrationEvent aEvent( *this, _Name, sOldLocation, _NewLocation );
352 0 : aGuard.clear();
353 0 : m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::changedDatabaseLocation, aEvent );
354 0 : }
355 :
356 0 : sal_Bool SAL_CALL DatabaseRegistrations::isDatabaseRegistrationReadOnly( const OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException, std::exception)
357 : {
358 0 : ::osl::MutexGuard aGuard( m_aMutex );
359 0 : ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_exist(_Name);
360 0 : return aDataSourceRegistration.isReadonly();
361 : }
362 :
363 3 : void SAL_CALL DatabaseRegistrations::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException, std::exception)
364 : {
365 3 : if ( _Listener.is() )
366 3 : m_aRegistrationListeners.addInterface( _Listener );
367 3 : }
368 :
369 1 : void SAL_CALL DatabaseRegistrations::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException, std::exception)
370 : {
371 1 : if ( _Listener.is() )
372 1 : m_aRegistrationListeners.removeInterface( _Listener );
373 1 : }
374 :
375 : // DatabaseRegistrations - factory
376 20 : Reference< XAggregation > createDataSourceRegistrations( const Reference<XComponentContext> & _rxContext )
377 : {
378 20 : return new DatabaseRegistrations( _rxContext );
379 : }
380 :
381 : } // namespace dbaccess
382 :
383 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|