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 <unotools/configvaluecontainer.hxx>
21 : #include <unotools/confignode.hxx>
22 : #include <tools/debug.hxx>
23 : #include <uno/data.h>
24 : #include <algorithm>
25 : #include <vector>
26 :
27 : #ifdef DBG_UTIL
28 : #include <rtl/strbuf.hxx>
29 : #endif
30 :
31 : namespace utl
32 : {
33 :
34 : using namespace ::com::sun::star::uno;
35 : using namespace ::com::sun::star::lang;
36 :
37 : //= NodeValueAccessor
38 :
39 : enum LocationType
40 : {
41 : ltSimplyObjectInstance,
42 : ltAnyInstance,
43 :
44 : ltUnbound
45 : };
46 :
47 0 : struct NodeValueAccessor
48 : {
49 : private:
50 : OUString sRelativePath; // the relative path of the node
51 : LocationType eLocationType; // the type of location where the value is stored
52 : void* pLocation; // the pointer to the location
53 : Type aDataType; // the type object pointed to by pLocation
54 :
55 : public:
56 : NodeValueAccessor( const OUString& _rNodePath );
57 :
58 : void bind( void* _pLocation, const Type& _rType );
59 :
60 : bool isBound( ) const { return ( ltUnbound != eLocationType ) && ( NULL != pLocation ); }
61 0 : const OUString& getPath( ) const { return sRelativePath; }
62 0 : LocationType getLocType( ) const { return eLocationType; }
63 0 : void* getLocation( ) const { return pLocation; }
64 0 : const Type& getDataType( ) const { return aDataType; }
65 :
66 : bool operator == ( const NodeValueAccessor& rhs ) const;
67 : };
68 :
69 0 : NodeValueAccessor::NodeValueAccessor( const OUString& _rNodePath )
70 : :sRelativePath( _rNodePath )
71 : ,eLocationType( ltUnbound )
72 0 : ,pLocation( NULL )
73 : {
74 0 : }
75 :
76 0 : bool NodeValueAccessor::operator == ( const NodeValueAccessor& rhs ) const
77 : {
78 0 : return ( sRelativePath == rhs.sRelativePath )
79 0 : && ( eLocationType == rhs.eLocationType )
80 0 : && ( pLocation == rhs.pLocation );
81 : }
82 :
83 0 : void NodeValueAccessor::bind( void* _pLocation, const Type& _rType )
84 : {
85 : DBG_ASSERT( !isBound(), "NodeValueAccessor::bind: already bound!" );
86 :
87 0 : eLocationType = ltSimplyObjectInstance;
88 0 : pLocation = _pLocation;
89 0 : aDataType = _rType;
90 0 : }
91 :
92 : #ifndef UNX
93 : static
94 : #endif
95 0 : void lcl_copyData( const NodeValueAccessor& _rAccessor, const Any& _rData, ::osl::Mutex& _rMutex )
96 : {
97 0 : ::osl::MutexGuard aGuard( _rMutex );
98 :
99 : DBG_ASSERT( _rAccessor.isBound(), "::utl::lcl_copyData: invalid accessor!" );
100 0 : switch ( _rAccessor.getLocType() )
101 : {
102 : case ltSimplyObjectInstance:
103 : {
104 0 : if ( _rData.hasValue() )
105 : {
106 : #ifdef DBG_UTIL
107 : bool bSuccess =
108 : #endif
109 : // assign the value
110 : uno_type_assignData(
111 0 : _rAccessor.getLocation(), _rAccessor.getDataType().getTypeLibType(),
112 0 : const_cast< void* >( _rData.getValue() ), _rData.getValueType().getTypeLibType(),
113 : (uno_QueryInterfaceFunc)cpp_queryInterface, (uno_AcquireFunc)cpp_acquire, (uno_ReleaseFunc)cpp_release
114 0 : );
115 : #ifdef DBG_UTIL
116 : OStringBuffer aBuf( 256 );
117 : aBuf.append("::utl::lcl_copyData( Accessor, Any ): could not assign the data (node path: ");
118 : aBuf.append( OUStringToOString( _rAccessor.getPath(), RTL_TEXTENCODING_ASCII_US ) );
119 : aBuf.append( " !" );
120 : DBG_ASSERT( bSuccess, aBuf.getStr() );
121 : #endif
122 : }
123 : else {
124 : DBG_WARNING( "::utl::lcl_copyData: NULL value lost!" );
125 : }
126 : }
127 0 : break;
128 : case ltAnyInstance:
129 : // a simple assignment of an Any ...
130 0 : *static_cast< Any* >( _rAccessor.getLocation() ) = _rData;
131 0 : break;
132 : default:
133 0 : break;
134 0 : }
135 0 : }
136 :
137 : #ifndef UNX
138 : static
139 : #endif
140 0 : void lcl_copyData( Any& _rData, const NodeValueAccessor& _rAccessor, ::osl::Mutex& _rMutex )
141 : {
142 0 : ::osl::MutexGuard aGuard( _rMutex );
143 :
144 : DBG_ASSERT( _rAccessor.isBound(), "::utl::lcl_copyData: invalid accessor!" );
145 0 : switch ( _rAccessor.getLocType() )
146 : {
147 : case ltSimplyObjectInstance:
148 : // a simple setValue ....
149 0 : _rData.setValue( _rAccessor.getLocation(), _rAccessor.getDataType() );
150 0 : break;
151 :
152 : case ltAnyInstance:
153 : // a simple assignment of an Any ...
154 0 : _rData = *static_cast< Any* >( _rAccessor.getLocation() );
155 0 : break;
156 : default:
157 0 : break;
158 0 : }
159 0 : }
160 :
161 : //= functors on NodeValueAccessor instances
162 :
163 : /// base class for functors syncronizing between exchange locations and config sub nodes
164 : struct SubNodeAccess : public ::std::unary_function< NodeValueAccessor, void >
165 : {
166 : protected:
167 : const OConfigurationNode& m_rRootNode;
168 : ::osl::Mutex& m_rMutex;
169 :
170 : public:
171 0 : SubNodeAccess( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex )
172 : :m_rRootNode( _rRootNode )
173 0 : ,m_rMutex( _rMutex )
174 : {
175 0 : }
176 : };
177 :
178 : struct UpdateFromConfig : public SubNodeAccess
179 : {
180 : public:
181 0 : UpdateFromConfig( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex ) : SubNodeAccess( _rRootNode, _rMutex ) { }
182 :
183 0 : void operator() ( NodeValueAccessor& _rAccessor )
184 : {
185 0 : ::utl::lcl_copyData( _rAccessor, m_rRootNode.getNodeValue( _rAccessor.getPath( ) ), m_rMutex );
186 0 : }
187 : };
188 :
189 : struct UpdateToConfig : public SubNodeAccess
190 : {
191 : public:
192 0 : UpdateToConfig( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex ) : SubNodeAccess( _rRootNode, _rMutex ) { }
193 :
194 0 : void operator() ( NodeValueAccessor& _rAccessor )
195 : {
196 0 : Any aNewValue;
197 0 : lcl_copyData( aNewValue, _rAccessor, m_rMutex );
198 0 : m_rRootNode.setNodeValue( _rAccessor.getPath( ), aNewValue );
199 0 : }
200 : };
201 :
202 : typedef std::vector<NodeValueAccessor> NodeValueAccessors;
203 :
204 : //= OConfigurationValueContainerImpl
205 :
206 0 : struct OConfigurationValueContainerImpl
207 : {
208 : Reference< XComponentContext > xORB; // the service factory
209 : ::osl::Mutex& rMutex; // the mutex for accessing the data containers
210 : OConfigurationTreeRoot aConfigRoot; // the configuration node we're accessing
211 :
212 : NodeValueAccessors aAccessors; // the accessors to the node values
213 :
214 0 : OConfigurationValueContainerImpl( const Reference< XComponentContext >& _rxORB, ::osl::Mutex& _rMutex )
215 : :xORB( _rxORB )
216 0 : ,rMutex( _rMutex )
217 : {
218 0 : }
219 : };
220 :
221 : //= OConfigurationValueContainer
222 :
223 0 : OConfigurationValueContainer::OConfigurationValueContainer(
224 : const Reference< XComponentContext >& _rxORB, ::osl::Mutex& _rAccessSafety,
225 : const sal_Char* _pConfigLocation, const sal_uInt16 _nAccessFlags, const sal_Int32 _nLevels )
226 0 : :m_pImpl( new OConfigurationValueContainerImpl( _rxORB, _rAccessSafety ) )
227 : {
228 0 : implConstruct( OUString::createFromAscii( _pConfigLocation ), _nAccessFlags, _nLevels );
229 0 : }
230 :
231 0 : OConfigurationValueContainer::~OConfigurationValueContainer()
232 : {
233 0 : delete m_pImpl;
234 0 : }
235 :
236 0 : void OConfigurationValueContainer::implConstruct( const OUString& _rConfigLocation,
237 : const sal_uInt16 _nAccessFlags, const sal_Int32 _nLevels )
238 : {
239 : DBG_ASSERT( !m_pImpl->aConfigRoot.isValid(), "OConfigurationValueContainer::implConstruct: already initialized!" );
240 :
241 : // create the configuration node we're about to work with
242 0 : m_pImpl->aConfigRoot = OConfigurationTreeRoot::createWithComponentContext(
243 : m_pImpl->xORB,
244 : _rConfigLocation,
245 : _nLevels,
246 0 : ( _nAccessFlags & CVC_UPDATE_ACCESS ) ? OConfigurationTreeRoot::CM_UPDATABLE : OConfigurationTreeRoot::CM_READONLY,
247 0 : ( _nAccessFlags & CVC_IMMEDIATE_UPDATE ) ? sal_False : sal_True
248 0 : );
249 : #ifdef DBG_UTIL
250 : OStringBuffer aBuf(256);
251 : aBuf.append("Could not access the configuration node located at ");
252 : aBuf.append( OUStringToOString( _rConfigLocation, RTL_TEXTENCODING_ASCII_US ) );
253 : aBuf.append( " !" );
254 : DBG_ASSERT( m_pImpl->aConfigRoot.isValid(), aBuf.getStr() );
255 : #endif
256 0 : }
257 :
258 0 : void OConfigurationValueContainer::registerExchangeLocation( const sal_Char* _pRelativePath,
259 : void* _pContainer, const Type& _rValueType )
260 : {
261 : // checks ....
262 : DBG_ASSERT( _pContainer, "OConfigurationValueContainer::registerExchangeLocation: invalid container location!" );
263 : DBG_ASSERT( ( TypeClass_CHAR == _rValueType.getTypeClass( ) )
264 : || ( TypeClass_BOOLEAN == _rValueType.getTypeClass( ) )
265 : || ( TypeClass_BYTE == _rValueType.getTypeClass( ) )
266 : || ( TypeClass_SHORT == _rValueType.getTypeClass( ) )
267 : || ( TypeClass_LONG == _rValueType.getTypeClass( ) )
268 : || ( TypeClass_DOUBLE == _rValueType.getTypeClass( ) )
269 : || ( TypeClass_STRING == _rValueType.getTypeClass( ) )
270 : || ( TypeClass_SEQUENCE == _rValueType.getTypeClass( ) ),
271 : "OConfigurationValueContainer::registerExchangeLocation: invalid type!" );
272 :
273 : // build an accessor for this container
274 0 : NodeValueAccessor aNewAccessor( OUString::createFromAscii( _pRelativePath ) );
275 0 : aNewAccessor.bind( _pContainer, _rValueType );
276 :
277 : // insert it into our structure
278 0 : implRegisterExchangeLocation( aNewAccessor );
279 0 : }
280 :
281 0 : void OConfigurationValueContainer::read( )
282 : {
283 : std::for_each(
284 : m_pImpl->aAccessors.begin(),
285 : m_pImpl->aAccessors.end(),
286 : UpdateFromConfig( m_pImpl->aConfigRoot, m_pImpl->rMutex )
287 0 : );
288 0 : }
289 :
290 0 : void OConfigurationValueContainer::write( bool _bCommit )
291 : {
292 : // collect the current values in the exchange locations
293 : std::for_each(
294 : m_pImpl->aAccessors.begin(),
295 : m_pImpl->aAccessors.end(),
296 : UpdateToConfig( m_pImpl->aConfigRoot, m_pImpl->rMutex )
297 0 : );
298 :
299 : // commit the changes done (if requested)
300 0 : if ( _bCommit )
301 0 : commit( false );
302 0 : }
303 :
304 0 : void OConfigurationValueContainer::commit( bool _bWrite )
305 : {
306 : // write the current values in the exchange locations (if requested)
307 0 : if ( _bWrite )
308 0 : write( false );
309 :
310 : // commit the changes done
311 0 : m_pImpl->aConfigRoot.commit( );
312 0 : }
313 :
314 0 : void OConfigurationValueContainer::implRegisterExchangeLocation( const NodeValueAccessor& _rAccessor )
315 : {
316 : // some checks
317 : DBG_ASSERT( !m_pImpl->aConfigRoot.isValid() || m_pImpl->aConfigRoot.hasByHierarchicalName( _rAccessor.getPath() ),
318 : "OConfigurationValueContainer::implRegisterExchangeLocation: invalid relative path!" );
319 :
320 : #ifdef DBG_UTIL
321 : // another check (should be the first container for this node)
322 : NodeValueAccessors::const_iterator aExistent = ::std::find(
323 : m_pImpl->aAccessors.begin(),
324 : m_pImpl->aAccessors.end(),
325 : _rAccessor
326 : );
327 : DBG_ASSERT( m_pImpl->aAccessors.end() == aExistent, "OConfigurationValueContainer::implRegisterExchangeLocation: already registered a container for this subnode!" );
328 : #endif
329 :
330 : // remember the accessor
331 0 : m_pImpl->aAccessors.push_back( _rAccessor );
332 :
333 : // and initially fill the value
334 0 : lcl_copyData( _rAccessor, m_pImpl->aConfigRoot.getNodeValue( _rAccessor.getPath() ), m_pImpl->rMutex );
335 0 : }
336 :
337 : } // namespace utl
338 :
339 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|