LibreOffice Module comphelper (master)  1
instancelocker.cxx
Go to the documentation of this file.
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 
23 
24 #include <com/sun/star/util/CloseVetoException.hpp>
25 #include <com/sun/star/util/XCloseBroadcaster.hpp>
26 #include <com/sun/star/util/XCloseable.hpp>
27 #include <com/sun/star/lang/DisposedException.hpp>
28 #include <com/sun/star/lang/IllegalArgumentException.hpp>
29 #include <com/sun/star/frame/XDesktop.hpp>
30 #include <com/sun/star/frame/TerminationVetoException.hpp>
31 #include <com/sun/star/frame/DoubleInitializationException.hpp>
32 #include <com/sun/star/embed/Actions.hpp>
33 #include <com/sun/star/embed/XActionsApproval.hpp>
34 
35 #include "instancelocker.hxx"
36 
37 namespace com::sun::star::uno { class XComponentContext; }
38 
39 using namespace ::com::sun::star;
40 
41 
42 // OInstanceLocker
43 
44 
46 : m_bDisposed( false )
47 , m_bInitialized( false )
48 {
49 }
50 
51 
53 {
54  if ( !m_bDisposed )
55  {
56  osl_atomic_increment(&m_refCount); // to call dispose
57  try {
58  dispose();
59  }
60  catch ( uno::RuntimeException& )
61  {}
62  }
63 }
64 
65 // XComponent
66 
67 void SAL_CALL OInstanceLocker::dispose()
68 {
69  ::osl::MutexGuard aGuard( m_aMutex );
70 
71  if ( m_bDisposed )
72  throw lang::DisposedException();
73 
74  lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) );
76  m_pListenersContainer->disposeAndClear( aSource );
77 
78  if ( m_xLockListener.is() )
79  {
80  m_xLockListener->Dispose();
81  m_xLockListener.clear();
82  }
83 
84  m_bDisposed = true;
85 }
86 
87 
88 void SAL_CALL OInstanceLocker::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
89 {
90  ::osl::MutexGuard aGuard( m_aMutex );
91  if ( m_bDisposed )
92  throw lang::DisposedException(); // TODO
93 
94  if ( !m_pListenersContainer )
95  m_pListenersContainer.reset( new ::comphelper::OInterfaceContainerHelper2( m_aMutex ) );
96 
97  m_pListenersContainer->addInterface( xListener );
98 }
99 
100 
101 void SAL_CALL OInstanceLocker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
102 {
103  ::osl::MutexGuard aGuard( m_aMutex );
104  if ( m_pListenersContainer )
105  m_pListenersContainer->removeInterface( xListener );
106 }
107 
108 // XInitialization
109 
110 void SAL_CALL OInstanceLocker::initialize( const uno::Sequence< uno::Any >& aArguments )
111 {
112  ::osl::MutexGuard aGuard( m_aMutex );
113  if ( m_bInitialized )
114  throw frame::DoubleInitializationException();
115 
116  if ( m_bDisposed )
117  throw lang::DisposedException(); // TODO
118 
119  if ( !m_refCount )
120  throw uno::RuntimeException(); // the object must be refcounted already!
121 
122  uno::Reference< uno::XInterface > xInstance;
123  uno::Reference< embed::XActionsApproval > xApproval;
124  sal_Int32 nModes = 0;
125 
126  try
127  {
128  sal_Int32 nLen = aArguments.getLength();
129  if ( nLen < 2 || nLen > 3 )
130  throw lang::IllegalArgumentException(
131  "Wrong count of parameters!",
132  uno::Reference< uno::XInterface >(),
133  0 );
134 
135  if ( !( aArguments[0] >>= xInstance ) || !xInstance.is() )
136  throw lang::IllegalArgumentException(
137  "Nonempty reference is expected as the first argument!",
138  uno::Reference< uno::XInterface >(),
139  0 );
140 
141  if (
142  !( aArguments[1] >>= nModes ) ||
143  (
144  !( nModes & embed::Actions::PREVENT_CLOSE ) &&
145  !( nModes & embed::Actions::PREVENT_TERMINATION )
146  )
147  )
148  {
149  throw lang::IllegalArgumentException(
150  "The correct modes set is expected as the second argument!",
151  uno::Reference< uno::XInterface >(),
152  0 );
153  }
154 
155  if ( nLen == 3 && !( aArguments[2] >>= xApproval ) )
156  throw lang::IllegalArgumentException(
157  "If the third argument is provided, it must be XActionsApproval implementation!",
158  uno::Reference< uno::XInterface >(),
159  0 );
160 
161  m_xLockListener = new OLockListener( uno::Reference< lang::XComponent > ( static_cast< lang::XComponent* >( this ) ),
162  xInstance,
163  nModes,
164  xApproval );
165  m_xLockListener->Init();
166  }
167  catch( uno::Exception& )
168  {
169  dispose();
170  throw;
171  }
172 
173  m_bInitialized = true;
174 }
175 
176 // XServiceInfo
178 {
179  return "com.sun.star.comp.embed.InstanceLocker";
180 }
181 
182 sal_Bool SAL_CALL OInstanceLocker::supportsService( const OUString& ServiceName )
183 {
184  return cppu::supportsService(this, ServiceName);
185 }
186 
187 uno::Sequence< OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames()
188 {
189  return { "com.sun.star.embed.InstanceLocker" };
190 }
191 
192 // OLockListener
193 
194 
195 OLockListener::OLockListener( const uno::WeakReference< lang::XComponent >& xWrapper,
196  const uno::Reference< uno::XInterface >& xInstance,
197  sal_Int32 nMode,
198  const uno::Reference< embed::XActionsApproval >& rApproval )
199 : m_xInstance( xInstance )
200 , m_xApproval( rApproval )
201 , m_xWrapper( xWrapper )
202 , m_bDisposed( false )
203 , m_bInitialized( false )
204 , m_nMode( nMode )
205 {
206 }
207 
208 
210 {
211 }
212 
213 
215 {
216  osl::MutexGuard aGuard( m_aMutex );
217 
218  if ( m_bDisposed )
219  return;
220 
221  if ( m_nMode & embed::Actions::PREVENT_CLOSE )
222  {
223  try
224  {
225  uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY );
226  if ( xCloseBroadcaster.is() )
227  xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
228 
229  uno::Reference< util::XCloseable > xCloseable( m_xInstance, uno::UNO_QUERY );
230  if ( xCloseable.is() )
231  xCloseable->close( true );
232  }
233  catch( uno::Exception& )
234  {}
235  }
236 
237  if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
238  {
239  try
240  {
241  uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
242  xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
243  }
244  catch( uno::Exception& )
245  {}
246  }
247 
248  m_xInstance.clear();
249  m_bDisposed = true;
250 }
251 
252 // XEventListener
253 
254 void SAL_CALL OLockListener::disposing( const lang::EventObject& aEvent )
255 {
256  osl::ClearableMutexGuard aGuard( m_aMutex );
257 
258  // object is disposed
259  if ( aEvent.Source != m_xInstance )
260  return;
261 
262  // the object does not listen for anything any more
263  m_nMode = 0;
264 
265  // dispose the wrapper;
266  uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
267  aGuard.clear();
268  if ( xComponent.is() )
269  {
270  try { xComponent->dispose(); }
271  catch( uno::Exception& ){}
272  }
273 }
274 
275 
276 // XCloseListener
277 
278 void SAL_CALL OLockListener::queryClosing( const lang::EventObject& aEvent, sal_Bool )
279 {
280  // GetsOwnership parameter is always ignored, the user of the service must close the object always
281  osl::ClearableMutexGuard aGuard( m_aMutex );
282  if ( !(!m_bDisposed && aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_CLOSE )) )
283  return;
284 
285  try
286  {
287  uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
288 
289  // unlock the mutex here
290  aGuard.clear();
291 
292  if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_CLOSE ) )
293  throw util::CloseVetoException();
294  }
295  catch( util::CloseVetoException& )
296  {
297  // rethrow this exception
298  throw;
299  }
300  catch( uno::Exception& )
301  {
302  // no action should be done
303  }
304 }
305 
306 
307 void SAL_CALL OLockListener::notifyClosing( const lang::EventObject& aEvent )
308 {
309  osl::ClearableMutexGuard aGuard( m_aMutex );
310 
311  // object is closed, no reason to listen
312  if ( aEvent.Source != m_xInstance )
313  return;
314 
315  uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( aEvent.Source, uno::UNO_QUERY );
316  if ( !xCloseBroadcaster.is() )
317  return;
318 
319  xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
320  m_nMode &= ~embed::Actions::PREVENT_CLOSE;
321  if ( !m_nMode )
322  {
323  // dispose the wrapper;
324  uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
325  aGuard.clear();
326  if ( xComponent.is() )
327  {
328  try { xComponent->dispose(); }
329  catch( uno::Exception& ){}
330  }
331  }
332 }
333 
334 
335 // XTerminateListener
336 
337 void SAL_CALL OLockListener::queryTermination( const lang::EventObject& aEvent )
338 {
339  osl::ClearableMutexGuard aGuard( m_aMutex );
340  if ( !(aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_TERMINATION )) )
341  return;
342 
343  try
344  {
345  uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
346 
347  // unlock the mutex here
348  aGuard.clear();
349 
350  if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_TERMINATION ) )
351  throw frame::TerminationVetoException();
352  }
353  catch( frame::TerminationVetoException& )
354  {
355  // rethrow this exception
356  throw;
357  }
358  catch( uno::Exception& )
359  {
360  // no action should be done
361  }
362 }
363 
364 
365 void SAL_CALL OLockListener::notifyTermination( const lang::EventObject& aEvent )
366 {
367  osl::ClearableMutexGuard aGuard( m_aMutex );
368 
369  // object is terminated, no reason to listen
370  if ( aEvent.Source != m_xInstance )
371  return;
372 
373  uno::Reference< frame::XDesktop > xDesktop( aEvent.Source, uno::UNO_QUERY );
374  if ( !xDesktop.is() )
375  return;
376 
377  try
378  {
379  xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
380  m_nMode &= ~embed::Actions::PREVENT_TERMINATION;
381  if ( !m_nMode )
382  {
383  // dispose the wrapper;
384  uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
385  aGuard.clear();
386  if ( xComponent.is() )
387  {
388  try { xComponent->dispose(); }
389  catch( uno::Exception& ){}
390  }
391  }
392  }
393  catch( uno::Exception& )
394  {}
395 }
396 
397 
398 // XInitialization
399 
401 {
402  osl::ClearableMutexGuard aGuard( m_aMutex );
403 
404  if ( m_bDisposed || m_bInitialized )
405  return;
406 
407  try
408  {
409  if ( m_nMode & embed::Actions::PREVENT_CLOSE )
410  {
411  uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY_THROW );
412  xCloseBroadcaster->addCloseListener( static_cast< util::XCloseListener* >( this ) );
413  }
414 
415  if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
416  {
417  uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
418  xDesktop->addTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
419  }
420  }
421  catch( uno::Exception& )
422  {
423  // dispose the wrapper;
424  uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
425  aGuard.clear();
426  if ( xComponent.is() )
427  {
428  try { xComponent->dispose(); }
429  catch( uno::Exception& ){}
430  }
431 
432  throw;
433  }
434 
435  m_bInitialized = true;
436 }
437 
438 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
440  css::uno::XComponentContext *,
441  css::uno::Sequence<css::uno::Any> const &)
442 {
443  return cppu::acquire(new OInstanceLocker());
444 }
445 
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void SAL_CALL dispose() override
::osl::Mutex m_aMutex
css::uno::Reference< css::embed::XActionsApproval > m_xApproval
virtual void SAL_CALL notifyTermination(const css::lang::EventObject &Event) override
bool m_bDisposed
ULONG m_refCount
sal_Int32 m_nMode
exports com.sun.star. embed
virtual void SAL_CALL queryTermination(const css::lang::EventObject &Event) override
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
::osl::Mutex m_aMutex
virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &aArguments) override
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_embed_InstanceLocker(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
rtl::Reference< OLockListener > m_xLockListener
virtual OUString SAL_CALL getImplementationName() override
css::uno::Reference< css::lang::XComponent > xComponent
std::unique_ptr<::comphelper::OInterfaceContainerHelper2 > m_pListenersContainer
unsigned char sal_Bool
virtual ~OInstanceLocker() override
virtual void SAL_CALL notifyClosing(const css::lang::EventObject &Source) override
OLockListener(const css::uno::WeakReference< css::lang::XComponent > &xWrapper, const css::uno::Reference< css::uno::XInterface > &xInstance, sal_Int32 nMode, const css::uno::Reference< css::embed::XActionsApproval > &rApproval)
css::uno::Reference< css::uno::XInterface > m_xInstance
virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener > &aListener) override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
css::uno::WeakReference< css::lang::XComponent > m_xWrapper
virtual ~OLockListener() override
virtual void SAL_CALL queryClosing(const css::lang::EventObject &Source, sal_Bool GetsOwnership) override
AnyEventRef aEvent