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