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