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