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