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 
34 #include <classes/propertysethelper.hxx>
35 #include <threadhelp/transactionguard.hxx>
36 #include <threadhelp/readguard.hxx>
37 #include <threadhelp/writeguard.hxx>
38 
39 //_________________________________________________________________________________________________________________
40 //	interface includes
41 
42 //_________________________________________________________________________________________________________________
43 //	other includes
44 
45 //_________________________________________________________________________________________________________________
46 //	namespace
47 
48 namespace framework{
49 
50 //_________________________________________________________________________________________________________________
51 //  non exported definitions
52 
53 //-----------------------------------------------------------------------------
54 PropertySetHelper::PropertySetHelper(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR                       ,
55                                            LockHelper*                                             pExternalLock               ,
56                                            TransactionManager*                                     pExternalTransactionManager ,
57                                            sal_Bool                                                bReleaseLockOnCall          )
58     : m_xSMGR                (xSMGR                                )
59     , m_lSimpleChangeListener(pExternalLock->getShareableOslMutex())
60     , m_lVetoChangeListener  (pExternalLock->getShareableOslMutex())
61     , m_bReleaseLockOnCall   (bReleaseLockOnCall                   )
62     , m_rLock                (*pExternalLock                       )
63     , m_rTransactionManager  (*pExternalTransactionManager         )
64 {
65 }
66 
67 //-----------------------------------------------------------------------------
68 PropertySetHelper::~PropertySetHelper()
69 {
70 }
71 
72 //-----------------------------------------------------------------------------
73 void PropertySetHelper::impl_setPropertyChangeBroadcaster(const css::uno::Reference< css::uno::XInterface >& xBroadcaster)
74 {
75     TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);
76 
77     // SAFE ->
78     WriteGuard aWriteLock(m_rLock);
79     m_xBroadcaster = xBroadcaster;
80     aWriteLock.unlock();
81     // <- SAFE
82 }
83 
84 //-----------------------------------------------------------------------------
85 void SAL_CALL PropertySetHelper::impl_addPropertyInfo(const css::beans::Property& aProperty)
86     throw(css::beans::PropertyExistException,
87           css::uno::Exception               )
88 {
89     TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);
90 
91     // SAFE ->
92     WriteGuard aWriteLock(m_rLock);
93 
94     PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(aProperty.Name);
95     if (pIt != m_lProps.end())
96         throw css::beans::PropertyExistException();
97 
98     m_lProps[aProperty.Name] = aProperty;
99     // <- SAFE
100 }
101 
102 //-----------------------------------------------------------------------------
103 void SAL_CALL PropertySetHelper::impl_removePropertyInfo(const ::rtl::OUString& sProperty)
104     throw(css::beans::UnknownPropertyException,
105           css::uno::Exception                 )
106 {
107     TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);
108 
109     // SAFE ->
110     WriteGuard aWriteLock(m_rLock);
111 
112     PropertySetHelper::TPropInfoHash::iterator pIt = m_lProps.find(sProperty);
113     if (pIt == m_lProps.end())
114         throw css::beans::UnknownPropertyException();
115 
116     m_lProps.erase(pIt);
117     // <- SAFE
118 }
119 
120 //-----------------------------------------------------------------------------
121 void SAL_CALL PropertySetHelper::impl_enablePropertySet()
122 {
123 }
124 
125 //-----------------------------------------------------------------------------
126 void SAL_CALL PropertySetHelper::impl_disablePropertySet()
127 {
128     TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);
129 
130     // SAFE ->
131     WriteGuard aWriteLock(m_rLock);
132 
133     css::uno::Reference< css::uno::XInterface > xThis(static_cast< css::beans::XPropertySet* >(this), css::uno::UNO_QUERY);
134     css::lang::EventObject aEvent(xThis);
135 
136     m_lSimpleChangeListener.disposeAndClear(aEvent);
137     m_lVetoChangeListener.disposeAndClear(aEvent);
138     m_lProps.free();
139 
140     aWriteLock.unlock();
141     // <- SAFE
142 }
143 
144 //-----------------------------------------------------------------------------
145 sal_Bool PropertySetHelper::impl_existsVeto(const css::beans::PropertyChangeEvent& aEvent)
146 {
147     /*  Dont use the lock here!
148         The used helper is threadsafe and it lives for the whole lifetime of
149         our own object.
150     */
151     ::cppu::OInterfaceContainerHelper* pVetoListener = m_lVetoChangeListener.getContainer(aEvent.PropertyName);
152 	if (! pVetoListener)
153         return sal_False;
154 
155 	::cppu::OInterfaceIteratorHelper pListener(*pVetoListener);
156 	while (pListener.hasMoreElements())
157 	{
158         try
159         {
160             css::uno::Reference< css::beans::XVetoableChangeListener > xListener(
161                 ((css::beans::XVetoableChangeListener*)pListener.next()),
162                 css::uno::UNO_QUERY_THROW);
163             xListener->vetoableChange(aEvent);
164         }
165         catch(const css::uno::RuntimeException&)
166             { pListener.remove(); }
167         catch(const css::beans::PropertyVetoException&)
168             { return sal_True; }
169 	}
170 
171     return sal_False;
172 }
173 
174 //-----------------------------------------------------------------------------
175 void PropertySetHelper::impl_notifyChangeListener(const css::beans::PropertyChangeEvent& aEvent)
176 {
177     /*  Dont use the lock here!
178         The used helper is threadsafe and it lives for the whole lifetime of
179         our own object.
180     */
181     ::cppu::OInterfaceContainerHelper* pSimpleListener = m_lSimpleChangeListener.getContainer(aEvent.PropertyName);
182 	if (! pSimpleListener)
183         return;
184 
185 	::cppu::OInterfaceIteratorHelper pListener(*pSimpleListener);
186 	while (pListener.hasMoreElements())
187 	{
188         try
189         {
190             css::uno::Reference< css::beans::XPropertyChangeListener > xListener(
191                 ((css::beans::XVetoableChangeListener*)pListener.next()),
192                 css::uno::UNO_QUERY_THROW);
193             xListener->propertyChange(aEvent);
194         }
195         catch(const css::uno::RuntimeException&)
196             { pListener.remove(); }
197 	}
198 }
199 
200 //-----------------------------------------------------------------------------
201 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PropertySetHelper::getPropertySetInfo()
202     throw(css::uno::RuntimeException)
203 {
204     TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);
205 
206     css::uno::Reference< css::beans::XPropertySetInfo > xInfo(static_cast< css::beans::XPropertySetInfo* >(this), css::uno::UNO_QUERY_THROW);
207     return xInfo;
208 }
209 
210 //-----------------------------------------------------------------------------
211 void SAL_CALL PropertySetHelper::setPropertyValue(const ::rtl::OUString& sProperty,
212                                                   const css::uno::Any&   aValue   )
213     throw(css::beans::UnknownPropertyException,
214           css::beans::PropertyVetoException   ,
215           css::lang::IllegalArgumentException ,
216           css::lang::WrappedTargetException   ,
217           css::uno::RuntimeException          )
218 {
219     // TODO look for e.g. readonly props and reject setProp() call!
220 
221     TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);
222 
223     // SAFE ->
224     WriteGuard aWriteLock(m_rLock);
225 
226     PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
227     if (pIt == m_lProps.end())
228         throw css::beans::UnknownPropertyException();
229 
230     css::beans::Property aPropInfo = pIt->second;
231 
232     sal_Bool bLocked = sal_True;
233     if (m_bReleaseLockOnCall)
234     {
235         aWriteLock.unlock();
236         bLocked = sal_False;
237         // <- SAFE
238     }
239 
240     css::uno::Any aCurrentValue = impl_getPropertyValue(aPropInfo.Name, aPropInfo.Handle);
241 
242     if (! bLocked)
243     {
244         // SAFE ->
245         aWriteLock.lock();
246         bLocked = sal_True;
247     }
248 
249     sal_Bool bWillBeChanged = (aCurrentValue != aValue);
250     if (! bWillBeChanged)
251         return;
252 
253     css::beans::PropertyChangeEvent aEvent;
254     aEvent.PropertyName   = aPropInfo.Name;
255     aEvent.Further        = sal_False;
256     aEvent.PropertyHandle = aPropInfo.Handle;
257     aEvent.OldValue       = aCurrentValue;
258     aEvent.NewValue       = aValue;
259     aEvent.Source         = css::uno::Reference< css::uno::XInterface >(m_xBroadcaster.get(), css::uno::UNO_QUERY);
260 
261     if (m_bReleaseLockOnCall)
262     {
263         aWriteLock.unlock();
264         bLocked = sal_False;
265         // <- SAFE
266     }
267 
268     if (impl_existsVeto(aEvent))
269         throw css::beans::PropertyVetoException();
270 
271     impl_setPropertyValue(aPropInfo.Name, aPropInfo.Handle, aValue);
272 
273     impl_notifyChangeListener(aEvent);
274 }
275 
276 //-----------------------------------------------------------------------------
277 css::uno::Any SAL_CALL PropertySetHelper::getPropertyValue(const ::rtl::OUString& sProperty)
278     throw(css::beans::UnknownPropertyException,
279           css::lang::WrappedTargetException   ,
280           css::uno::RuntimeException          )
281 {
282     TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);
283 
284     // SAFE ->
285     ReadGuard aReadLock(m_rLock);
286 
287     PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
288     if (pIt == m_lProps.end())
289         throw css::beans::UnknownPropertyException();
290 
291     css::beans::Property aPropInfo = pIt->second;
292 
293     sal_Bool bLocked = sal_True;
294     if (m_bReleaseLockOnCall)
295     {
296         aReadLock.unlock();
297         bLocked = sal_False;
298         // <- SAFE
299     }
300 
301     return impl_getPropertyValue(aPropInfo.Name, aPropInfo.Handle);
302 }
303 
304 //-----------------------------------------------------------------------------
305 void SAL_CALL PropertySetHelper::addPropertyChangeListener(const ::rtl::OUString&                                            sProperty,
306                                                            const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener)
307     throw(css::beans::UnknownPropertyException,
308           css::lang::WrappedTargetException   ,
309           css::uno::RuntimeException          )
310 {
311     TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);
312 
313     // SAFE ->
314     ReadGuard aReadLock(m_rLock);
315 
316     PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
317     if (pIt == m_lProps.end())
318         throw css::beans::UnknownPropertyException();
319 
320     aReadLock.unlock();
321     // <- SAFE
322 
323     m_lSimpleChangeListener.addInterface(sProperty, xListener);
324 }
325 
326 //-----------------------------------------------------------------------------
327 void SAL_CALL PropertySetHelper::removePropertyChangeListener(const ::rtl::OUString&                                            sProperty,
328                                                               const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener)
329     throw(css::beans::UnknownPropertyException,
330           css::lang::WrappedTargetException   ,
331           css::uno::RuntimeException          )
332 {
333     TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);
334 
335     // SAFE ->
336     ReadGuard aReadLock(m_rLock);
337 
338     PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
339     if (pIt == m_lProps.end())
340         throw css::beans::UnknownPropertyException();
341 
342     aReadLock.unlock();
343     // <- SAFE
344 
345     m_lSimpleChangeListener.removeInterface(sProperty, xListener);
346 }
347 
348 //-----------------------------------------------------------------------------
349 void SAL_CALL PropertySetHelper::addVetoableChangeListener(const ::rtl::OUString&                                            sProperty,
350                                                            const css::uno::Reference< css::beans::XVetoableChangeListener >& xListener)
351     throw(css::beans::UnknownPropertyException,
352           css::lang::WrappedTargetException   ,
353           css::uno::RuntimeException          )
354 {
355     TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);
356 
357     // SAFE ->
358     ReadGuard aReadLock(m_rLock);
359 
360     PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
361     if (pIt == m_lProps.end())
362         throw css::beans::UnknownPropertyException();
363 
364     aReadLock.unlock();
365     // <- SAFE
366 
367     m_lVetoChangeListener.addInterface(sProperty, xListener);
368 }
369 
370 //-----------------------------------------------------------------------------
371 void SAL_CALL PropertySetHelper::removeVetoableChangeListener(const ::rtl::OUString&                                            sProperty,
372                                                               const css::uno::Reference< css::beans::XVetoableChangeListener >& xListener)
373     throw(css::beans::UnknownPropertyException,
374           css::lang::WrappedTargetException   ,
375           css::uno::RuntimeException          )
376 {
377     TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);
378 
379     // SAFE ->
380     ReadGuard aReadLock(m_rLock);
381 
382     PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
383     if (pIt == m_lProps.end())
384         throw css::beans::UnknownPropertyException();
385 
386     aReadLock.unlock();
387     // <- SAFE
388 
389     m_lVetoChangeListener.removeInterface(sProperty, xListener);
390 }
391 
392 //-----------------------------------------------------------------------------
393 css::uno::Sequence< css::beans::Property > SAL_CALL PropertySetHelper::getProperties()
394     throw(css::uno::RuntimeException)
395 {
396     TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);
397 
398     // SAFE ->
399     ReadGuard aReadLock(m_rLock);
400 
401     sal_Int32                                        c     = (sal_Int32)m_lProps.size();
402     css::uno::Sequence< css::beans::Property >       lProps(c);
403     PropertySetHelper::TPropInfoHash::const_iterator pIt   ;
404 
405     for (  pIt  = m_lProps.begin();
406            pIt != m_lProps.end()  ;
407          ++pIt                    )
408     {
409         lProps[--c] = pIt->second;
410     }
411 
412     return lProps;
413     // <- SAFE
414 }
415 
416 //-----------------------------------------------------------------------------
417 css::beans::Property SAL_CALL PropertySetHelper::getPropertyByName(const ::rtl::OUString& sName)
418     throw(css::beans::UnknownPropertyException,
419           css::uno::RuntimeException          )
420 {
421     TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);
422 
423     // SAFE ->
424     ReadGuard aReadLock(m_rLock);
425 
426     PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sName);
427     if (pIt == m_lProps.end())
428         throw css::beans::UnknownPropertyException();
429 
430     return pIt->second;
431     // <- SAFE
432 }
433 
434 //-----------------------------------------------------------------------------
435 sal_Bool SAL_CALL PropertySetHelper::hasPropertyByName(const ::rtl::OUString& sName)
436     throw(css::uno::RuntimeException)
437 {
438     TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);
439 
440     // SAFE ->
441     ReadGuard aReadLock(m_rLock);
442 
443     PropertySetHelper::TPropInfoHash::iterator pIt    = m_lProps.find(sName);
444     sal_Bool                                   bExist = (pIt != m_lProps.end());
445 
446     return bExist;
447     // <- SAFE
448 }
449 
450 } // namespace framework
451