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