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