1     /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
30 
31 //________________________________
32 //	my own includes
33 #include <jobs/configaccess.hxx>
34 #include <threadhelp/readguard.hxx>
35 #include <threadhelp/writeguard.hxx>
36 #include <threadhelp/resetableguard.hxx>
37 #include <general.h>
38 #include <services.h>
39 
40 //________________________________
41 //	interface includes
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/beans/XMultiHierarchicalPropertySet.hpp>
44 #include <com/sun/star/container/XNameAccess.hpp>
45 #include <com/sun/star/beans/PropertyValue.hpp>
46 #include <com/sun/star/util/XChangesBatch.hpp>
47 
48 //________________________________
49 //	includes of other projects
50 #include <unotools/configpathes.hxx>
51 #include <rtl/ustrbuf.hxx>
52 
53 //________________________________
54 //	namespace
55 
56 namespace framework{
57 
58 //________________________________
59 //	non exported const
60 
61 //________________________________
62 //	non exported definitions
63 
64 //________________________________
65 //	declarations
66 
67 //________________________________
68 /**
69     @short  open the configuration of this job
70     @descr  We open the configuration of this job only. Not the whole package or the whole
71             job set. We are interested on our own properties only.
72             We set the opened configuration access as our member. So any following method,
73             which needs cfg access, can use it. That prevent us against multiple open/close requests.
74             But you can use this method to upgrade an already opened configuration too.
75 
76     @param  eMode
77                 force opening of the configuration access in readonly or in read/write mode
78  */
79 ConfigAccess::ConfigAccess( /*IN*/ const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
80                             /*IN*/ const ::rtl::OUString&                                        sRoot )
81     : ThreadHelpBase(          )
82     , m_xSMGR       ( xSMGR    )
83     , m_sRoot       ( sRoot    )
84     , m_eMode       ( E_CLOSED )
85 {
86 }
87 
88 //________________________________
89 /**
90     @short  last chance to close an open configuration access point
91     @descr  In case our user forgot to close this configuration point
92             in the right way, normaly he will run into some trouble -
93             e.g. losing data.
94  */
95 ConfigAccess::~ConfigAccess()
96 {
97     close();
98 }
99 
100 //________________________________
101 /**
102     @short  return the internal mode of this instance
103     @descr  May be the outside user need any information about successfully opened
104             or closed config access point objects. He can control the internal mode to do so.
105 
106     @return The internal open state of this object.
107  */
108 ConfigAccess::EOpenMode ConfigAccess::getMode() const
109 {
110     /* SAFE { */
111     ReadGuard aReadLock(m_aLock);
112     return m_eMode;
113     /* } SAFE */
114 }
115 
116 //________________________________
117 /**
118     @short  open the configuration access in the specified mode
119     @descr  We set the opened configuration access as our member. So any following method,
120             which needs cfg access, can use it. That prevent us against multiple open/close requests.
121             But you can use this method to upgrade an already opened configuration too.
122             It's possible to open a config access in READONLY mode first and "open" it at a second
123             time within the mode READWRITE. Then we will upgrade it. Dowgrade will be possible too.
124 
125             But note: closing will be done explicitly by calling method close() ... not by
126             downgrading with mode CLOSED!
127 
128     @param  eMode
129                 force (re)opening of the configuration access in readonly or in read/write mode
130  */
131 void ConfigAccess::open( /*IN*/ EOpenMode eMode )
132 {
133     /* SAFE { */
134     // We must lock the whole method to be shure, that nobody
135     // outside uses our internal member m_xAccess!
136     WriteGuard aWriteLock(m_aLock);
137 
138     // check if configuration is already open in the right mode.
139     // By the way: Don't allow closing by using this method!
140     if (
141         (eMode  !=E_CLOSED) &&
142         (m_eMode!=eMode   )
143        )
144     {
145         // We have to close the old access point without any question here.
146         // It will be open again using the new mode.
147         // can be called without checks! It does the checks by itself ...
148         // e.g. for already closed or not opened configuration.
149         // Flushing of all made changes will be done here too.
150         close();
151 
152         // create the configuration provider, which provides sub access points
153         css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(m_xSMGR->createInstance(SERVICENAME_CFGPROVIDER), css::uno::UNO_QUERY);
154         if (xConfigProvider.is())
155         {
156             css::beans::PropertyValue aParam;
157             aParam.Name    = DECLARE_ASCII("nodepath");
158             aParam.Value <<= m_sRoot;
159 
160             css::uno::Sequence< css::uno::Any > lParams(1);
161             lParams[0] <<= aParam;
162 
163             // open it
164             try
165             {
166                 if (eMode==E_READONLY)
167                     m_xConfig = xConfigProvider->createInstanceWithArguments(SERVICENAME_CFGREADACCESS  , lParams);
168                 else
169                 if (eMode==E_READWRITE)
170                     m_xConfig = xConfigProvider->createInstanceWithArguments(SERVICENAME_CFGUPDATEACCESS, lParams);
171             }
172             catch(css::uno::Exception& ex)
173             {
174                 (void) ex; // avoid warning
175                 LOG_WARNING("open config ...", U2B(ex.Message))
176             }
177 
178             m_eMode = E_CLOSED;
179             if (m_xConfig.is())
180                 m_eMode = eMode;
181         }
182     }
183 
184     aWriteLock.unlock();
185     /* } SAFE */
186 }
187 
188 //________________________________
189 /**
190     @short  close the internal opened configuration access and flush all changes
191     @descr  It checks, if the given access is valid and react in the right way.
192             It flushes all changes ... so nobody else must know this state.
193  */
194 void ConfigAccess::close()
195 {
196     /* SAFE { */
197     // Lock the whole method, to be shure that nobody else uses our internal members
198     // during this time.
199     WriteGuard aWriteLock(m_aLock);
200 
201     // check already closed configuration
202     if (m_xConfig.is())
203     {
204         css::uno::Reference< css::util::XChangesBatch > xFlush(m_xConfig, css::uno::UNO_QUERY);
205         if (xFlush.is())
206             xFlush->commitChanges();
207         m_xConfig = css::uno::Reference< css::uno::XInterface >();
208         m_eMode   = E_CLOSED;
209     }
210 
211     aWriteLock.unlock();
212     /* } SAFE */
213 }
214 
215 //________________________________
216 /**
217     @short  provides an access to the internal wrapped configuration access
218     @descr  It's not allowed to safe this c++ (!) reference outside. You have
219             to use it directly. Further you must use our public lock member m_aLock
220             to synchronize your code with our internal structures and our interface
221             methods. Acquire it before you call cfg() and release it afterwards immediatly.
222 
223             E.g.:   ConfigAccess aAccess(...);
224                     ReadGuard aReadLock(aAccess.m_aLock);
225                     Reference< XPropertySet > xSet(aAccess.cfg(), UNO_QUERY);
226                     Any aProp = xSet->getPropertyValue("...");
227                     aReadLock.unlock();
228 
229     @attention  During this time it's not allowed to call the methods open() or close()!
230                 Otherwhise you will change your own referenced config access. Anything will
231                 be possible then.
232 
233     @return A c++(!) reference to the uno instance of the configuration access point.
234  */
235 const css::uno::Reference< css::uno::XInterface >& ConfigAccess::cfg()
236 {
237     // must be synchronized from outside!
238     // => no lock here ...
239     return m_xConfig;
240 }
241 
242 } // namespace framework
243