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 throw (uno::RuntimeException)
81 {
82 ::osl::MutexGuard aGuard( m_aMutex );
83
84 if ( m_bDisposed )
85 throw lang::DisposedException();
86
87 lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) );
88 if ( m_pListenersContainer )
89 m_pListenersContainer->disposeAndClear( aSource );
90
91 if ( m_xLockListener.is() )
92 {
93 if ( m_pLockListener )
94 {
95 m_pLockListener->Dispose();
96 m_pLockListener = NULL;
97 }
98 m_xLockListener = uno::Reference< uno::XInterface >();
99 }
100
101 m_bDisposed = sal_True;
102 }
103
104 // --------------------------------------------------------
addEventListener(const uno::Reference<lang::XEventListener> & xListener)105 void SAL_CALL OInstanceLocker::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
106 throw (uno::RuntimeException)
107 {
108 ::osl::MutexGuard aGuard( m_aMutex );
109 if ( m_bDisposed )
110 throw lang::DisposedException(); // TODO
111
112 if ( !m_pListenersContainer )
113 m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutex );
114
115 m_pListenersContainer->addInterface( xListener );
116 }
117
118 // --------------------------------------------------------
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)119 void SAL_CALL OInstanceLocker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
120 throw (uno::RuntimeException)
121 {
122 ::osl::MutexGuard aGuard( m_aMutex );
123 if ( m_pListenersContainer )
124 m_pListenersContainer->removeInterface( xListener );
125 }
126
127 // XInitialization
128 // --------------------------------------------------------
initialize(const uno::Sequence<uno::Any> & aArguments)129 void SAL_CALL OInstanceLocker::initialize( const uno::Sequence< uno::Any >& aArguments )
130 throw (uno::Exception, uno::RuntimeException)
131 {
132 ::osl::MutexGuard aGuard( m_aMutex );
133 if ( m_bInitialized )
134 throw frame::DoubleInitializationException();
135
136 if ( m_bDisposed )
137 throw lang::DisposedException(); // TODO
138
139 if ( !m_refCount )
140 throw uno::RuntimeException(); // the object must be refcounted already!
141
142 uno::Reference< uno::XInterface > xInstance;
143 uno::Reference< embed::XActionsApproval > xApproval;
144 sal_Int32 nModes = 0;
145
146 try
147 {
148 sal_Int32 nLen = aArguments.getLength();
149 if ( nLen < 2 || nLen > 3 )
150 throw lang::IllegalArgumentException(
151 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Wrong count of parameters!" ) ),
152 uno::Reference< uno::XInterface >(),
153 0 );
154
155 if ( !( aArguments[0] >>= xInstance ) || !xInstance.is() )
156 throw lang::IllegalArgumentException(
157 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Nonempty reference is expected as the first argument!" ) ),
158 uno::Reference< uno::XInterface >(),
159 0 );
160
161 if (
162 !( aArguments[1] >>= nModes ) ||
163 (
164 !( nModes & embed::Actions::PREVENT_CLOSE ) &&
165 !( nModes & embed::Actions::PREVENT_TERMINATION )
166 )
167 )
168 {
169 throw lang::IllegalArgumentException(
170 ::rtl::OUString(
171 RTL_CONSTASCII_USTRINGPARAM("The correct modes set is expected as the second argument!" ) ),
172 uno::Reference< uno::XInterface >(),
173 0 );
174 }
175
176 if ( nLen == 3 && !( aArguments[2] >>= xApproval ) )
177 throw lang::IllegalArgumentException(
178 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("If the third argument is provided, it must be XActionsApproval implementation!" ) ),
179 uno::Reference< uno::XInterface >(),
180 0 );
181
182 m_pLockListener = new OLockListener( uno::Reference< lang::XComponent > ( static_cast< lang::XComponent* >( this ) ),
183 xInstance,
184 nModes,
185 xApproval );
186 m_xLockListener = uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( m_pLockListener ) );
187 m_pLockListener->Init();
188 }
189 catch( uno::Exception& )
190 {
191 dispose();
192 throw;
193 }
194
195 m_bInitialized = sal_True;
196 }
197
198
199 // XServiceInfo
200 // --------------------------------------------------------
getImplementationName()201 ::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName( )
202 throw (uno::RuntimeException)
203 {
204 return getImplementationName_static();
205 }
206
207 // --------------------------------------------------------
supportsService(const::rtl::OUString & ServiceName)208 ::sal_Bool SAL_CALL OInstanceLocker::supportsService( const ::rtl::OUString& ServiceName )
209 throw (uno::RuntimeException)
210 {
211 uno::Sequence< ::rtl::OUString > aSeq = getSupportedServiceNames();
212
213 for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
214 if ( ServiceName.compareTo( aSeq[nInd] ) == 0 )
215 return sal_True;
216
217 return sal_False;
218 }
219
220 // --------------------------------------------------------
getSupportedServiceNames()221 uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames()
222 throw (uno::RuntimeException)
223 {
224 return getSupportedServiceNames_static();
225 }
226
227 // Static methods
228 // --------------------------------------------------------
getSupportedServiceNames_static()229 uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames_static()
230 {
231 const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.InstanceLocker" ) );
232 return uno::Sequence< rtl::OUString >( &aServiceName, 1 );
233 }
234
235 // --------------------------------------------------------
getImplementationName_static()236 ::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName_static()
237 {
238 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.embed.InstanceLocker" ) );
239 }
240
241 // --------------------------------------------------------
Create(const uno::Reference<uno::XComponentContext> & rxContext)242 uno::Reference< uno::XInterface > SAL_CALL OInstanceLocker::Create(
243 const uno::Reference< uno::XComponentContext >& rxContext )
244 {
245 return static_cast< cppu::OWeakObject * >( new OInstanceLocker( rxContext ) );
246 }
247
248
249
250 // ====================================================================
251 // OLockListener
252 // ====================================================================
253
254 // --------------------------------------------------------
OLockListener(const uno::WeakReference<lang::XComponent> & xWrapper,const uno::Reference<uno::XInterface> & xInstance,sal_Int32 nMode,const uno::Reference<embed::XActionsApproval> xApproval)255 OLockListener::OLockListener( const uno::WeakReference< lang::XComponent >& xWrapper,
256 const uno::Reference< uno::XInterface >& xInstance,
257 sal_Int32 nMode,
258 const uno::Reference< embed::XActionsApproval > xApproval )
259 : m_xInstance( xInstance )
260 , m_xApproval( xApproval )
261 , m_xWrapper( xWrapper )
262 , m_bDisposed( sal_False )
263 , m_bInitialized( sal_False )
264 , m_nMode( nMode )
265 {
266 }
267
268 // --------------------------------------------------------
~OLockListener()269 OLockListener::~OLockListener()
270 {
271 }
272
273 // --------------------------------------------------------
Dispose()274 void OLockListener::Dispose()
275 {
276 ::osl::ResettableMutexGuard aGuard( m_aMutex );
277
278 if ( m_bDisposed )
279 return;
280
281 if ( m_nMode & embed::Actions::PREVENT_CLOSE )
282 {
283 try
284 {
285 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY );
286 if ( xCloseBroadcaster.is() )
287 xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
288
289 uno::Reference< util::XCloseable > xCloseable( m_xInstance, uno::UNO_QUERY );
290 if ( xCloseable.is() )
291 xCloseable->close( sal_True );
292 }
293 catch( uno::Exception& )
294 {}
295 }
296
297 if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
298 {
299 try
300 {
301 uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
302 xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
303 }
304 catch( uno::Exception& )
305 {}
306 }
307
308 m_xInstance = uno::Reference< uno::XInterface >();
309 m_bDisposed = sal_True;
310 }
311
312 // XEventListener
313 // --------------------------------------------------------
disposing(const lang::EventObject & aEvent)314 void SAL_CALL OLockListener::disposing( const lang::EventObject& aEvent )
315 throw (uno::RuntimeException)
316 {
317 ::osl::ResettableMutexGuard aGuard( m_aMutex );
318
319 // object is disposed
320 if ( aEvent.Source == m_xInstance )
321 {
322 // the object does not listen for anything any more
323 m_nMode = 0;
324
325 // dispose the wrapper;
326 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
327 aGuard.clear();
328 if ( xComponent.is() )
329 {
330 try { xComponent->dispose(); }
331 catch( uno::Exception& ){}
332 }
333 }
334 }
335
336
337 // XCloseListener
338 // --------------------------------------------------------
queryClosing(const lang::EventObject & aEvent,sal_Bool)339 void SAL_CALL OLockListener::queryClosing( const lang::EventObject& aEvent, sal_Bool )
340 throw (util::CloseVetoException, uno::RuntimeException)
341 {
342 // GetsOwnership parameter is always ignored, the user of the service must close the object always
343 ::osl::ResettableMutexGuard aGuard( m_aMutex );
344 if ( !m_bDisposed && aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_CLOSE ) )
345 {
346 try
347 {
348 uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
349
350 // unlock the mutex here
351 aGuard.clear();
352
353 if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_CLOSE ) )
354 throw util::CloseVetoException();
355 }
356 catch( util::CloseVetoException& )
357 {
358 // rethrow this exception
359 throw;
360 }
361 catch( uno::Exception& )
362 {
363 // no action should be done
364 }
365 }
366 }
367
368 // --------------------------------------------------------
notifyClosing(const lang::EventObject & aEvent)369 void SAL_CALL OLockListener::notifyClosing( const lang::EventObject& aEvent )
370 throw (uno::RuntimeException)
371 {
372 ::osl::ResettableMutexGuard aGuard( m_aMutex );
373
374 // object is closed, no reason to listen
375 if ( aEvent.Source == m_xInstance )
376 {
377 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( aEvent.Source, uno::UNO_QUERY );
378 if ( xCloseBroadcaster.is() )
379 {
380 xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
381 m_nMode &= ~embed::Actions::PREVENT_CLOSE;
382 if ( !m_nMode )
383 {
384 // dispose the wrapper;
385 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
386 aGuard.clear();
387 if ( xComponent.is() )
388 {
389 try { xComponent->dispose(); }
390 catch( uno::Exception& ){}
391 }
392 }
393 }
394 }
395 }
396
397
398 // XTerminateListener
399 // --------------------------------------------------------
queryTermination(const lang::EventObject & aEvent)400 void SAL_CALL OLockListener::queryTermination( const lang::EventObject& aEvent )
401 throw (frame::TerminationVetoException, uno::RuntimeException)
402 {
403 ::osl::ResettableMutexGuard aGuard( m_aMutex );
404 if ( aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_TERMINATION ) )
405 {
406 try
407 {
408 uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
409
410 // unlock the mutex here
411 aGuard.clear();
412
413 if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_TERMINATION ) )
414 throw frame::TerminationVetoException();
415 }
416 catch( frame::TerminationVetoException& )
417 {
418 // rethrow this exception
419 throw;
420 }
421 catch( uno::Exception& )
422 {
423 // no action should be done
424 }
425 }
426 }
427
428 // --------------------------------------------------------
notifyTermination(const lang::EventObject & aEvent)429 void SAL_CALL OLockListener::notifyTermination( const lang::EventObject& aEvent )
430 throw (uno::RuntimeException)
431 {
432 ::osl::ResettableMutexGuard aGuard( m_aMutex );
433
434 // object is terminated, no reason to listen
435 if ( aEvent.Source == m_xInstance )
436 {
437 uno::Reference< frame::XDesktop > xDesktop( aEvent.Source, uno::UNO_QUERY );
438 if ( xDesktop.is() )
439 {
440 try
441 {
442 xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
443 m_nMode &= ~embed::Actions::PREVENT_TERMINATION;
444 if ( !m_nMode )
445 {
446 // dispose the wrapper;
447 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
448 aGuard.clear();
449 if ( xComponent.is() )
450 {
451 try { xComponent->dispose(); }
452 catch( uno::Exception& ){}
453 }
454 }
455 }
456 catch( uno::Exception& )
457 {}
458 }
459 }
460 }
461
462
463 // XInitialization
464 // --------------------------------------------------------
Init()465 sal_Bool OLockListener::Init()
466 {
467 ::osl::ResettableMutexGuard aGuard( m_aMutex );
468
469 if ( m_bDisposed || m_bInitialized )
470 return sal_False;
471
472 try
473 {
474 if ( m_nMode & embed::Actions::PREVENT_CLOSE )
475 {
476 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY_THROW );
477 xCloseBroadcaster->addCloseListener( static_cast< util::XCloseListener* >( this ) );
478 }
479
480 if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
481 {
482 uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
483 xDesktop->addTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
484 }
485 }
486 catch( uno::Exception& )
487 {
488 // dispose the wrapper;
489 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
490 aGuard.clear();
491 if ( xComponent.is() )
492 {
493 try { xComponent->dispose(); }
494 catch( uno::Exception& ){}
495 }
496
497 throw;
498 }
499
500 m_bInitialized = sal_True;
501
502 return sal_True;
503 }
504
createRegistryInfo_OInstanceLocker()505 void createRegistryInfo_OInstanceLocker()
506 {
507 static ::comphelper::module::OAutoRegistration< OInstanceLocker > aAutoRegistration;
508 }
509