xref: /trunk/main/comphelper/source/misc/instancelocker.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 
27 #include "comphelper_module.hxx"
28 
29 #include <com/sun/star/util/XCloseBroadcaster.hpp>
30 #include <com/sun/star/util/XCloseable.hpp>
31 #include <com/sun/star/lang/DisposedException.hpp>
32 #include <com/sun/star/lang/IllegalArgumentException.hpp>
33 #include <com/sun/star/frame/XDesktop.hpp>
34 #include <com/sun/star/frame/DoubleInitializationException.hpp>
35 #include <com/sun/star/frame/DoubleInitializationException.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 
38 #include "instancelocker.hxx"
39 
40 using namespace ::com::sun::star;
41 
42 
43 // ====================================================================
44 // OInstanceLocker
45 // ====================================================================
46 
47 // --------------------------------------------------------
OInstanceLocker(const uno::Reference<uno::XComponentContext> & xContext)48 OInstanceLocker::OInstanceLocker( const uno::Reference< uno::XComponentContext >& xContext )
49 : m_xContext( xContext )
50 , m_pLockListener( NULL )
51 , m_pListenersContainer( NULL )
52 , m_bDisposed( sal_False )
53 , m_bInitialized( sal_False )
54 {
55 }
56 
57 // --------------------------------------------------------
~OInstanceLocker()58 OInstanceLocker::~OInstanceLocker()
59 {
60     if ( !m_bDisposed )
61     {
62         m_refCount++; // to call dispose
63         try {
64             dispose();
65         }
66         catch ( uno::RuntimeException& )
67         {}
68     }
69 
70     if ( m_pListenersContainer )
71     {
72         delete m_pListenersContainer;
73         m_pListenersContainer = NULL;
74     }
75 }
76 
77 // XComponent
78 // --------------------------------------------------------
dispose()79 void SAL_CALL OInstanceLocker::dispose()
80 {
81     ::osl::MutexGuard aGuard( m_aMutex );
82 
83     if ( m_bDisposed )
84         throw lang::DisposedException();
85 
86     lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) );
87     if ( m_pListenersContainer )
88         m_pListenersContainer->disposeAndClear( aSource );
89 
90     if ( m_xLockListener.is() )
91     {
92         if ( m_pLockListener )
93         {
94             m_pLockListener->Dispose();
95             m_pLockListener = NULL;
96         }
97         m_xLockListener = uno::Reference< uno::XInterface >();
98     }
99 
100     m_bDisposed = sal_True;
101 }
102 
103 // --------------------------------------------------------
addEventListener(const uno::Reference<lang::XEventListener> & xListener)104 void SAL_CALL OInstanceLocker::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
105 {
106     ::osl::MutexGuard aGuard( m_aMutex );
107     if ( m_bDisposed )
108         throw lang::DisposedException(); // TODO
109 
110     if ( !m_pListenersContainer )
111         m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutex );
112 
113     m_pListenersContainer->addInterface( xListener );
114 }
115 
116 // --------------------------------------------------------
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)117 void SAL_CALL OInstanceLocker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
118 {
119     ::osl::MutexGuard aGuard( m_aMutex );
120     if ( m_pListenersContainer )
121         m_pListenersContainer->removeInterface( xListener );
122 }
123 
124 // XInitialization
125 // --------------------------------------------------------
initialize(const uno::Sequence<uno::Any> & aArguments)126 void SAL_CALL OInstanceLocker::initialize( const uno::Sequence< uno::Any >& aArguments )
127 {
128     ::osl::MutexGuard aGuard( m_aMutex );
129     if ( m_bInitialized )
130         throw frame::DoubleInitializationException();
131 
132     if ( m_bDisposed )
133         throw lang::DisposedException(); // TODO
134 
135     if ( !m_refCount )
136         throw uno::RuntimeException(); // the object must be refcounted already!
137 
138     uno::Reference< uno::XInterface > xInstance;
139     uno::Reference< embed::XActionsApproval > xApproval;
140     sal_Int32 nModes = 0;
141 
142     try
143     {
144         sal_Int32 nLen = aArguments.getLength();
145         if ( nLen < 2 || nLen > 3 )
146             throw lang::IllegalArgumentException(
147                             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Wrong count of parameters!" ) ),
148                             uno::Reference< uno::XInterface >(),
149                             0 );
150 
151         if ( !( aArguments[0] >>= xInstance ) || !xInstance.is() )
152             throw lang::IllegalArgumentException(
153                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Nonempty reference is expected as the first argument!" ) ),
154                     uno::Reference< uno::XInterface >(),
155                     0 );
156 
157         if (
158             !( aArguments[1] >>= nModes ) ||
159             (
160               !( nModes & embed::Actions::PREVENT_CLOSE ) &&
161               !( nModes & embed::Actions::PREVENT_TERMINATION )
162             )
163            )
164         {
165             throw lang::IllegalArgumentException(
166                     ::rtl::OUString(
167                             RTL_CONSTASCII_USTRINGPARAM("The correct modes set is expected as the second argument!" ) ),
168                     uno::Reference< uno::XInterface >(),
169                     0 );
170         }
171 
172         if ( nLen == 3 && !( aArguments[2] >>= xApproval ) )
173             throw lang::IllegalArgumentException(
174                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("If the third argument is provided, it must be XActionsApproval implementation!" ) ),
175                     uno::Reference< uno::XInterface >(),
176                     0 );
177 
178         m_pLockListener = new OLockListener( uno::Reference< lang::XComponent > ( static_cast< lang::XComponent* >( this ) ),
179                                             xInstance,
180                                             nModes,
181                                             xApproval );
182         m_xLockListener = uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( m_pLockListener ) );
183         m_pLockListener->Init();
184     }
185     catch( uno::Exception& )
186     {
187         dispose();
188         throw;
189     }
190 
191     m_bInitialized = sal_True;
192 }
193 
194 
195 // XServiceInfo
196 // --------------------------------------------------------
getImplementationName()197 ::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName(  )
198 {
199     return getImplementationName_static();
200 }
201 
202 // --------------------------------------------------------
supportsService(const::rtl::OUString & ServiceName)203 ::sal_Bool SAL_CALL OInstanceLocker::supportsService( const ::rtl::OUString& ServiceName )
204 {
205     uno::Sequence< ::rtl::OUString > aSeq = getSupportedServiceNames();
206 
207     for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
208         if ( ServiceName.compareTo( aSeq[nInd] ) == 0 )
209             return sal_True;
210 
211     return sal_False;
212 }
213 
214 // --------------------------------------------------------
getSupportedServiceNames()215 uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames()
216 {
217     return getSupportedServiceNames_static();
218 }
219 
220 // Static methods
221 // --------------------------------------------------------
getSupportedServiceNames_static()222 uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames_static()
223 {
224     const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.InstanceLocker" ) );
225     return uno::Sequence< rtl::OUString >( &aServiceName, 1 );
226 }
227 
228 // --------------------------------------------------------
getImplementationName_static()229 ::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName_static()
230 {
231     return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.embed.InstanceLocker" ) );
232 }
233 
234 // --------------------------------------------------------
Create(const uno::Reference<uno::XComponentContext> & rxContext)235 uno::Reference< uno::XInterface > SAL_CALL OInstanceLocker::Create(
236                                 const uno::Reference< uno::XComponentContext >& rxContext )
237 {
238     return static_cast< cppu::OWeakObject * >( new OInstanceLocker( rxContext ) );
239 }
240 
241 
242 
243 // ====================================================================
244 // OLockListener
245 // ====================================================================
246 
247 // --------------------------------------------------------
OLockListener(const uno::WeakReference<lang::XComponent> & xWrapper,const uno::Reference<uno::XInterface> & xInstance,sal_Int32 nMode,const uno::Reference<embed::XActionsApproval> xApproval)248 OLockListener::OLockListener( const uno::WeakReference< lang::XComponent >& xWrapper,
249                     const uno::Reference< uno::XInterface >& xInstance,
250                     sal_Int32 nMode,
251                     const uno::Reference< embed::XActionsApproval > xApproval )
252 : m_xInstance( xInstance )
253 , m_xApproval( xApproval )
254 , m_xWrapper( xWrapper )
255 , m_bDisposed( sal_False )
256 , m_bInitialized( sal_False )
257 , m_nMode( nMode )
258 {
259 }
260 
261 // --------------------------------------------------------
~OLockListener()262 OLockListener::~OLockListener()
263 {
264 }
265 
266 // --------------------------------------------------------
Dispose()267 void OLockListener::Dispose()
268 {
269     ::osl::ResettableMutexGuard aGuard( m_aMutex );
270 
271     if ( m_bDisposed )
272         return;
273 
274     if ( m_nMode & embed::Actions::PREVENT_CLOSE )
275     {
276         try
277         {
278             uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY );
279             if ( xCloseBroadcaster.is() )
280                 xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
281 
282             uno::Reference< util::XCloseable > xCloseable( m_xInstance, uno::UNO_QUERY );
283             if ( xCloseable.is() )
284                 xCloseable->close( sal_True );
285         }
286         catch( uno::Exception& )
287         {}
288     }
289 
290     if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
291     {
292         try
293         {
294             uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
295             xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
296         }
297         catch( uno::Exception& )
298         {}
299     }
300 
301     m_xInstance = uno::Reference< uno::XInterface >();
302     m_bDisposed = sal_True;
303 }
304 
305 // XEventListener
306 // --------------------------------------------------------
disposing(const lang::EventObject & aEvent)307 void SAL_CALL OLockListener::disposing( const lang::EventObject& aEvent )
308 {
309     ::osl::ResettableMutexGuard aGuard( m_aMutex );
310 
311     // object is disposed
312     if ( aEvent.Source == m_xInstance )
313     {
314         // the object does not listen for anything any more
315         m_nMode = 0;
316 
317         // dispose the wrapper;
318         uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
319         aGuard.clear();
320         if ( xComponent.is() )
321         {
322             try { xComponent->dispose(); }
323             catch( uno::Exception& ){}
324         }
325     }
326 }
327 
328 
329 // XCloseListener
330 // --------------------------------------------------------
queryClosing(const lang::EventObject & aEvent,sal_Bool)331 void SAL_CALL OLockListener::queryClosing( const lang::EventObject& aEvent, sal_Bool )
332 {
333     // GetsOwnership parameter is always ignored, the user of the service must close the object always
334     ::osl::ResettableMutexGuard aGuard( m_aMutex );
335     if ( !m_bDisposed && aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_CLOSE ) )
336     {
337         try
338         {
339             uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
340 
341             // unlock the mutex here
342             aGuard.clear();
343 
344             if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_CLOSE ) )
345                 throw util::CloseVetoException();
346         }
347         catch( util::CloseVetoException& )
348         {
349             // rethrow this exception
350             throw;
351         }
352         catch( uno::Exception& )
353         {
354             // no action should be done
355         }
356     }
357 }
358 
359 // --------------------------------------------------------
notifyClosing(const lang::EventObject & aEvent)360 void SAL_CALL OLockListener::notifyClosing( const lang::EventObject& aEvent )
361 {
362     ::osl::ResettableMutexGuard aGuard( m_aMutex );
363 
364     // object is closed, no reason to listen
365     if ( aEvent.Source == m_xInstance )
366     {
367         uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( aEvent.Source, uno::UNO_QUERY );
368         if ( xCloseBroadcaster.is() )
369         {
370             xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
371             m_nMode &= ~embed::Actions::PREVENT_CLOSE;
372             if ( !m_nMode )
373             {
374                 // dispose the wrapper;
375                 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
376                 aGuard.clear();
377                 if ( xComponent.is() )
378                 {
379                     try { xComponent->dispose(); }
380                     catch( uno::Exception& ){}
381                 }
382             }
383         }
384     }
385 }
386 
387 
388 // XTerminateListener
389 // --------------------------------------------------------
queryTermination(const lang::EventObject & aEvent)390 void SAL_CALL OLockListener::queryTermination( const lang::EventObject& aEvent )
391 {
392     ::osl::ResettableMutexGuard aGuard( m_aMutex );
393     if ( aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_TERMINATION ) )
394     {
395         try
396         {
397             uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
398 
399             // unlock the mutex here
400             aGuard.clear();
401 
402             if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_TERMINATION ) )
403                 throw frame::TerminationVetoException();
404         }
405         catch( frame::TerminationVetoException& )
406         {
407             // rethrow this exception
408             throw;
409         }
410         catch( uno::Exception& )
411         {
412             // no action should be done
413         }
414     }
415 }
416 
417 // --------------------------------------------------------
notifyTermination(const lang::EventObject & aEvent)418 void SAL_CALL OLockListener::notifyTermination( const lang::EventObject& aEvent )
419 {
420     ::osl::ResettableMutexGuard aGuard( m_aMutex );
421 
422     // object is terminated, no reason to listen
423     if ( aEvent.Source == m_xInstance )
424     {
425         uno::Reference< frame::XDesktop > xDesktop( aEvent.Source, uno::UNO_QUERY );
426         if ( xDesktop.is() )
427         {
428             try
429             {
430                 xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
431                 m_nMode &= ~embed::Actions::PREVENT_TERMINATION;
432                 if ( !m_nMode )
433                 {
434                     // dispose the wrapper;
435                     uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
436                     aGuard.clear();
437                     if ( xComponent.is() )
438                     {
439                         try { xComponent->dispose(); }
440                         catch( uno::Exception& ){}
441                     }
442                 }
443             }
444             catch( uno::Exception& )
445             {}
446         }
447     }
448 }
449 
450 
451 // XInitialization
452 // --------------------------------------------------------
Init()453 sal_Bool OLockListener::Init()
454 {
455     ::osl::ResettableMutexGuard aGuard( m_aMutex );
456 
457     if ( m_bDisposed || m_bInitialized )
458         return sal_False;
459 
460     try
461     {
462         if ( m_nMode & embed::Actions::PREVENT_CLOSE )
463         {
464             uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY_THROW );
465             xCloseBroadcaster->addCloseListener( static_cast< util::XCloseListener* >( this ) );
466         }
467 
468         if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
469         {
470             uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
471             xDesktop->addTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
472         }
473     }
474     catch( uno::Exception& )
475     {
476         // dispose the wrapper;
477         uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
478         aGuard.clear();
479         if ( xComponent.is() )
480         {
481             try { xComponent->dispose(); }
482             catch( uno::Exception& ){}
483         }
484 
485         throw;
486     }
487 
488     m_bInitialized = sal_True;
489 
490     return sal_True;
491 }
492 
createRegistryInfo_OInstanceLocker()493 void createRegistryInfo_OInstanceLocker()
494 {
495     static ::comphelper::module::OAutoRegistration< OInstanceLocker > aAutoRegistration;
496 }
497